2

我有以下代码片段(我认为)addNumber1(x:T):T在泛型类型上定义了一个方法,该泛型类型T是的子类型, AnyVal并且有一个方法+(s:Int):T

def addNumber1[T <: AnyVal {def +(s:Int):T}](x:T):T = {x + 1}

addNumber1(31) // compiles but throws exception

java.lang.NoSuchMethodException: java.lang.Integer.$plus(int)
  at java.lang.Class.getMethod(Class.java:1786)
  at .reflMethod$Method1(<console>:8)
  at .addNumber1(<console>:8)
  ... 33 elided

我尝试添加import scala.language.reflectiveCalls以抑制功能警告,但仍然出现错误。

我可以在以下情况下使用AnyRefAny

def addNumber1[T <: Any {def +(s:Int):T}](x:T):T = {x + 1}

class Foo(s:String) {def +(i:Int) = new Foo((s+1).toString)} // random code
class Bar(s:Foo) {def +(i:Int) = new Bar(new Foo(i.toString))} // random code

addNumber1(new Foo("1"))  // works
addNumber1(new Bar(new Foo("1")))  // works
addNumber1(1) // compiles but gives exception
4

2 回答 2

3

您遇到了很多功能的交集:

  1. 就 Scala 编译器的初始阶段(包括类型检查)而言,Int确实有一个(重载)+方法。但是这个“方法”在后期被特殊对待(就像所有方法一样Int,因为它不是一个真正的类)。

  2. 在 Scala 中调用+和定义的方法被转换为$plus在字节码中调用的方法,因为+那里不是合法的标识符。由于+onInt是特殊的,如上所述,这不适用于它。由于结构类型是使用 Java 反射实现的,因此您addNumber1看起来有点像

    def addNumber1(x: Object) = x.getClass.getMethod("$plus").invoke(x, 1)
    
  3. 要调用addNumber1an int,必须Integer先将其装箱,因为int它不是对象。Integer,不是 Scala 类型,没有$plus方法。在 Scala 中,您可以编写类似的东西val x: Integer = ...; x + 1,但这使用了 Java 反射不知道的隐式转换。

于 2016-09-05T09:30:01.893 回答
1

我认为这个问题与 AnyVal、AnyRef 或 Any 无关。

addNumber1(new Foo("1")) 

这是有效的,因为您确实定义了一个提供 def +(s:Int):T 实现的 Foo 类。

addNumber1(1)

这不起作用,因为 Integer 类不提供它,如异常中所述:

java.lang.NoSuchMethodException: java.lang.Integer.$plus(int)
于 2016-09-05T07:13:04.210 回答