为什么Scala不会在这里使用隐式转换?
我试图在
Java库
jOOQ中将这个set方法记录为
here,带有签名:
<T> ... set(Field<T> field,T value) 这个Scala系列是一个问题: .set(table.MODIFIED_BY,userId) MODIFIED_BY是Field< Integer>表示表列. userId是Int. Predef有一个从Int到Integer的隐式转换,那么它为什么不使用呢?我明白了: type mismatch; found: org.jooq.TableField[gen.tables.records.DocRecord,Integer] required: org.jooq.Field[Any] Note: Integer <: Any (and org.jooq.TableField[gen.tables.records.DocRecord,Integer] <: org.jooq.Field[Integer]),but Java-defined trait Field is invariant in type T. You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10) 更新 – 关于Vinicius的例子 这里不是试图在注释中解释这一点,而是演示当你使用带有协变参数的类型时没有调用隐式转换,比如List [T].假设我把这段代码放在一个文件中,编译并运行它…… case class Foo(str: String) object StackOver1 extends App { implicit def str2Foo(s: String): Foo = { println("In str2Foo.") new Foo(s) } def test[T](xs: List[T],x: T): List[T] = { println("test " + x.getClass) xs } val foo1 = new Foo("foo1") test(List(foo1),"abc") } 您将看到它调用test,但从未将字符串“abc”隐式转换为Foo.相反,它为test [T]选择一个T,它是String和Foo之间的公共基类.当你使用Int和Integer时,它选择Any,但是它很混乱,因为列表中Int的运行时表示是Integer.所以看起来它使用了隐式转换,但事实并非如此.您可以通过打开Scala提示进行验证… scala> :type StackOver1.test(List(new java.lang.Integer(1)),2) List[Any] 解决方法
我对jOOQ一无所知,但我认为问题在于Scala不能很好地理解java泛型.尝试:
scala> def test[T](a : java.util.ArrayList[T],b: T) = { println(a,b) } scala> val a = new java.util.ArrayList[Integer]() scala> val b = 12 scala> test(a,b) <console>:11: error: type mismatch; found : java.util.ArrayList[Integer] required: java.util.ArrayList[Any] Note: Integer <: Any,but Java-defined class ArrayList is invariant in type E. You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10) test(a,b) 听起来很熟悉?? 要修复,只需通知类型T调用方法:test [Integer](a,b)工作正常. 编辑: 这里涉及到一些事情: >擦除 – >编译时,通用的类型将通过擦除消失.编译器将使用Scala将被视为Any的Object.但是,ArrayList [Integer]不是ArrayList [Any],即使Integer是any.与TableField [gen.tables.records.DocRecord,Integer]相同的方式不是Field [Any]. 显示共同祖先如何用于确定T的示例: scala> def test[T](a: T,b: T): T = a scala> class Foo scala> class Boo extends Foo scala> test(new Boo,new Foo) res2: Foo = Boo@139c2a6 scala> test(new Boo,new Boo) res3: Boo = Boo@141c803 scala> class Coo extends Foo scala> test(new Boo,new Coo) res4: Foo = Boo@aafc83 scala> test(new Boo,"qsasad") res5: Object = Boo@16989d8 总而言之,隐式方法不会被调用,因为类型推断机制在获取参数之前确定类型,并且因为它使用共同的祖先,所以不需要隐式转换. 您的代码由于擦除机制而产生错误,该机制随类型信息消失,这对于确定参数的正确类型很重要. @RobN,感谢您质疑我的回答,我从这个过程中学到了很多东西. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |