gpt4 book ai didi

scala - 从 Scala 方法返回 AnyVal

转载 作者:行者123 更新时间:2023-12-03 03:35:56 26 4
gpt4 key购买 nike

任何人都可以解释为什么下面的 Scala 代码片段:

def convertRefToVal(obj: Any): Int = {
if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int]
else -1
}

convertRefToVal(42).getClass()

打印java.lang.Class[Int] = int,而:

def convertRefToVal(obj: Any): AnyVal = {
if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int]
else -1
}

convertRefToVal(42).getClass()

产生java.lang.Class[_] = class java.lang.Integer?

除了返回类型(Int 与 AnyVal)之外,这些方法是相同的。

因此,第一个示例返回 Int 值类型,而在第二种情况下,我得到 java.lang.Integer 引用类型作为结果。看起来自动装箱正在发生,但我不希望看到这种情况,因为第二个版本指定 AnyVal 作为其返回类型?

(我使用的是 Scala 2.10.2)

最佳答案

实际上,在函数的入口点,两个版本都应用了自动装箱,可能是因为 obj 需要为 Any。但有趣的是,当你考虑这些类型时:

def convertRefToVal(obj: Any): Int = {
println(obj.isInstanceOf[java.lang.Integer])
println(obj.isInstanceOf[Int])
println(obj.getClass())
if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int]
else -1
}
convertRefToVal(42)

打印:

true
true
class java.lang.Integer

因此,一个问题是,无论如何,java.lang.Integer 都被视为 Int 的实例。

无论如何,Scala 似乎有特定的支持,可以根据返回类型从包装器“转换”为基元。我将尝试找到原因的答案并在我的问题中进行编辑。

编辑:其他人可能会提供一个历史原因,但这里有一个事实原因。这是 javap 为两个函数打印的内容:

public int convertRefToVal(java.lang.Object); //first version
public java.lang.Object convertRefToVal1(java.lang.Object); //second version

因此,如您所见,从长远来看,AnyVal 映射到 java.lang.Object。事实上,这两个函数之间的区别在于,当两个都取消装箱先前自动装箱的参数时,第二个函数再次将其装箱。

为了演示,这里有一个示例类:

package stuff

object PrimTest {

def convertRefToVal(obj: Any): Int = {
if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int]
else -1
}

def convertRefToVal1(obj: Any): AnyVal = {
if (obj.isInstanceOf[java.lang.Integer]) obj.asInstanceOf[Int]
else -1
}

def main(args: Array[String]): Unit = {
new java.lang.Integer(42).asInstanceOf[Int] //added for isolating the cast example
}

}

这是java -p -v 输出:

  Compiled from "PrimTest.scala"
public final class stuff.PrimTest$
SourceFile: "PrimTest.scala"
Scala: length = 0x0

minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
Constant pool:
#1 = Utf8 stuff/PrimTest$
#2 = Class #1 // stuff/PrimTest$
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 PrimTest.scala
#6 = Utf8 MODULE$
#7 = Utf8 Lstuff/PrimTest$;
#8 = Utf8 <clinit>
#9 = Utf8 ()V
#10 = Utf8 <init>
#11 = NameAndType #10:#9 // "<init>":()V
#12 = Methodref #2.#11 // stuff/PrimTest$."<init>":()V
#13 = Utf8 convertRefToVal
#14 = Utf8 (Ljava/lang/Object;)I
#15 = Utf8 java/lang/Integer
#16 = Class #15 // java/lang/Integer
#17 = Utf8 scala/runtime/BoxesRunTime
#18 = Class #17 // scala/runtime/BoxesRunTime
#19 = Utf8 unboxToInt
#20 = NameAndType #19:#14 // unboxToInt:(Ljava/lang/Object;)I
#21 = Methodref #18.#20 // scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
#22 = Utf8 this
#23 = Utf8 obj
#24 = Utf8 Ljava/lang/Object;
#25 = Utf8 convertRefToVal1
#26 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object;
#27 = Utf8 boxToInteger
#28 = Utf8 (I)Ljava/lang/Integer;
#29 = NameAndType #27:#28 // boxToInteger:(I)Ljava/lang/Integer;
#30 = Methodref #18.#29 // scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
#31 = Utf8 main
#32 = Utf8 ([Ljava/lang/String;)V
#33 = Utf8 (I)V
#34 = NameAndType #10:#33 // "<init>":(I)V
#35 = Methodref #16.#34 // java/lang/Integer."<init>":(I)V
#36 = Utf8 args
#37 = Utf8 [Ljava/lang/String;
#38 = Methodref #4.#11 // java/lang/Object."<init>":()V
#39 = NameAndType #6:#7 // MODULE$:Lstuff/PrimTest$;
#40 = Fieldref #2.#39 // stuff/PrimTest$.MODULE$:Lstuff/PrimTest$;
#41 = Utf8 Code
#42 = Utf8 LocalVariableTable
#43 = Utf8 LineNumberTable
#44 = Utf8 StackMapTable
#45 = Utf8 SourceFile
#46 = Utf8 Scala
{
public static final stuff.PrimTest$ MODULE$;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL

public static {};
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: new #2 // class stuff/PrimTest$
3: invokespecial #12 // Method "<init>":()V
6: return

public int convertRefToVal(java.lang.Object);
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: aload_1
1: instanceof #16 // class java/lang/Integer
4: ifeq 14
7: aload_1
8: invokestatic #21 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
11: goto 15
14: iconst_m1
15: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this Lstuff/PrimTest$;
0 16 1 obj Ljava/lang/Object;
LineNumberTable:
line 6: 0
line 7: 14
line 6: 15
StackMapTable: number_of_entries = 2
frame_type = 14 /* same */
frame_type = 64 /* same_locals_1_stack_item */
stack = [ int ]


public java.lang.Object convertRefToVal1(java.lang.Object);
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: aload_1
1: instanceof #16 // class java/lang/Integer
4: ifeq 17
7: aload_1
8: invokestatic #21 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
11: invokestatic #30 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
14: goto 21
17: iconst_m1
18: invokestatic #30 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
21: areturn
LocalVariableTable:
Start Length Slot Name Signature
0 22 0 this Lstuff/PrimTest$;
0 22 1 obj Ljava/lang/Object;
LineNumberTable:
line 11: 0
line 12: 17
line 11: 21
StackMapTable: number_of_entries = 2
frame_type = 17 /* same */
frame_type = 67 /* same_locals_1_stack_item */
stack = [ class java/lang/Integer ]


public void main(java.lang.String[]);
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: new #16 // class java/lang/Integer
3: dup
4: bipush 42
6: invokespecial #35 // Method java/lang/Integer."<init>":(I)V
9: invokestatic #21 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
12: pop
13: return
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this Lstuff/PrimTest$;
0 14 1 args [Ljava/lang/String;
LineNumberTable:
line 16: 0

private stuff.PrimTest$();
flags: ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #38 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #40 // Field MODULE$:Lstuff/PrimTest$;
8: return
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lstuff/PrimTest$;
LineNumberTable:
line 3: 0
}

请注意 BoxesRunTime 调用的用法,顺便说一句,它实际上是一个 Java 类。这表明编译器中可能有一些特定的代码添加了这些调用。

关于scala - 从 Scala 方法返回 AnyVal,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17794625/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com