我定义了一个特征:
trait A {
def hello(name:Any):Any
}
然后定义一个类 X 来实现它:
class X extends A {
def hello(name:Any): Any = {}
}
它编译。然后我更改子类中的返回类型:
class X extends A {
def hello(name:Any): String = "hello"
}
它也编译了。然后更改参数类型:
class X extends A {
def hello(name:String): Any = {}
}
这次编译不了,报错是:
error: class X needs to be abstract, since method hello in trait A of type (name: Any)
Any is not defined
(Note that Any does not match String: class String in package lang is a subclass
of class Any in package scala, but method parameter types must match exactly.)
似乎参数应该完全匹配,但返回类型可以是子类中的子类型?
更新:@Mik378,感谢您的回答,但为什么下面的例子不能工作?我认为它不会破坏 Liskov:
trait A {
def hello(name:String):Any
}
class X extends A {
def hello(name:Any): Any = {}
}
最佳答案
就像在 Java 中一样,保持 Liskov Substitution principle ,你不能覆盖 具有更细粒度参数的方法。
确实,如果您的代码处理 A
怎么办?类型,引用 X
在引擎盖下键入。
根据 A
,您可以通过Any
输入你想要的,但 B
只允许 String
.
因此 => 繁荣
从逻辑上讲,根据相同的推理,允许使用更细粒度的返回类型,因为它会覆盖任何处理 A
的代码的情况。类(class)。
您可能需要检查这些部分:
http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Covariant_method_return_type
和
http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Contravariant_method_argument_type
更新 - - - - - - - -
trait A {
def hello(name:String):Any
}
class X extends A {
def hello(name:Any): Any = {}
}
它将充当完美的重载,而不是覆盖。
关于scala - 在 trait 中实现方法的规则是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23264695/