Getting java.lang.NoSuchMethodException in structural typing of AnyVal

限于喜欢 提交于 2020-05-23 10:37:33

问题


I have the following snippet that (I think) defines a method addNumber1(x:T):T on a generic type T which is a subtype of AnyVal and has a method +(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

I tried adding import scala.language.reflectiveCalls to suppress a feature warning but still get the error.

I am able to use this when working with AnyRef or Any as below:

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

回答1:


You run into an intersection of quite a few features:

  1. So far as the initial stages of Scala compiler are concerned (including typechecking), Int does have an (overloaded) + method. But this "method" is treated specially by the later stages (as are all methods on Int, because it isn't really a class).

  2. Methods called + and defined in Scala are translated to methods called $plus in bytecode, since + is not a legal identifier there. Since + on Int is special, as mentioned above, this doesn't apply to it. Since the structural types are implemented using Java reflection, your addNumber1 looks somewhat like

    def addNumber1(x: Object) = x.getClass.getMethod("$plus").invoke(x, 1)
    
  3. To call addNumber1 on an int, it has to be boxed to Integer first, because int is not an object. Integer, not being a Scala type, doesn't have a $plus method. In Scala you can write something like val x: Integer = ...; x + 1, but this uses an implicit conversion which Java reflection has no idea about.




回答2:


I think the problem has nothing to do with AnyVal, AnyRef Or Any.

addNumber1(new Foo("1")) 

This works because you indeed defined a Foo class that provides an implementation of def +(s:Int):T.

addNumber1(1)

This doesn't work because Integer class doesn't provide it, as is mentioned in the exception:

java.lang.NoSuchMethodException: java.lang.Integer.$plus(int)


来源:https://stackoverflow.com/questions/39315310/getting-java-lang-nosuchmethodexception-in-structural-typing-of-anyval

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!