简体   繁体   English

Scala和Java - 隐式参数和继承

[英]Scala and Java - Implicit Parameters and Inheritance

The following code gives an error: 以下代码给出了错误:

package test

trait Base {
  def method:String
}

trait Trait extends Base {
  def method()(implicit i:String):String = { "2" }
}

object Object extends Trait {

}

The error is "object creation impossible, since method method in class Base of type => String is not defined" 错误是“对象创建不可能,因为类型为Base的方法方法=>字符串未定义”

The above error is fixed by following code 以下错误由以下代码修复

package test

trait Base {
  def method:String
}

trait Trait extends Base {
  def method:String = method()("String") // Over loading
  def method()(implicit i:String):String = { "2" }
}

object Object extends Trait {

}

Now instead of Scala class, when I define a Java interface as follows: 现在我代替Scala类,当我定义一个Java接口时,如下所示:

// Java Code
package test;

public interface JBase {
  String method();
}

// Scala Code
package test

trait Trait extends JBase {
  def method:String = method()("10")
  def method()(implicit i:String):String = { "2" }
}

object Object extends Trait {

}

I get an error "ambiguous reference to overloaded definition, both method method in trait Trait of type ()(implicit i: String)String and method method in trait Trait of type ()String match argument types ()" 我得到一个错误“对重载定义的模糊引用,特征中的方法方法Traint of type()(隐式i:String)特征中的字符串和方法方法类型的特征()字符串匹配参数类型()”

What is the difference in both these scenarios that makes the compiler behave differently? 这两种场景的不同之处在于编译器的行为方式有何不同? How do I solve this issue? 我该如何解决这个问题?

Here's an example that I think shows clearly what is going on: 这是一个我认为清楚显示正在发生的事情的例子:

object Test extends App {
    class A { def f(): String = "x" }
    class B extends A { override def f: String = "y" }
    class C { def f: String = "z" }

    println { (new A).f() } // OK
    println { (new B).f() } // OK
    println { (new C).f() } // FAILS
}
  • A : Has parentheses, called with parentheses, everything good. A :有括号,用括号括起来,一切都很好。
  • B : Has no parentheses, but supertype does have parentheses, so still good. B没有括号,但是超类型确实有括号,所以仍然很好。 This corresponds to your case. 这符合您的情况。
  • C : Has no parentheses, called with parentheses, no good. C :没有括号,括号括起来,没有好处。

Basically, Java methods are always considered "with parentheses", so, Trait 's supertype has the parentheses, so using parentheses in method()("string") is insufficient to clarify which method you mean. 基本上,Java方法总是被认为是“括号”,因此, Trait的超类型具有括号,因此在method()("string")使用括号不足以阐明您的方法。


edit : Honestly I think you are better off renaming the method. 编辑 :老实说,我认为你最好重命名方法。 Even in the case where there is no ambiguity, the behavior could be quite surprising: 即使在没有歧义的情况下,行为也可能非常令人惊讶:

trait Trait {
    def method: String = method()("x")
    def method()(implicit i: String): String = i
}

val t = new Trait { }
implicit val s = "y"

println { t.method }
> "x"

println { t.method() }
> "y"

Furthermore, the fact that the name is the same isn't buying you anything in terms of polymorphism: only the non-implicit method overrides Base.method -- it's just an aesthetic decision to make the names be the same. 此外,名称相同的事实并不是就多态性而购买任何东西:只有非隐式方法会覆盖Base.method - 这只是一个美学决定,使名称相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM