Scala 什么';在trait中实现方法的规则是什么?
我定义了一个特征:Scala 什么';在trait中实现方法的规则是什么?,scala,types,extends,traits,Scala,Types,Extends,Traits,我定义了一个特征: 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 hel
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,谢谢你的回答,但是为什么下面的例子不起作用?我认为这并没有打断利斯科夫:
trait A {
def hello(name:String):Any
}
class X extends A {
def hello(name:Any): Any = {}
}
这与Java中的情况完全相同,您不能使用更细粒度的参数覆盖方法 实际上,如果您的代码处理
A
类型,引用引擎盖下的X
类型,该怎么办。
根据A
,您可以传递所需的任何类型,但B
只允许字符串。
因此=>繁荣
从逻辑上讲,使用相同的推理,允许使用更细粒度的返回类型,因为任何处理a
类的代码都会覆盖它,不管它是什么情况
您可能需要检查这些部件:
及
更新----------------
它将充当一个完美的重载,而不是重写。这是我不知道的,但基本上对于X.hello
来说,为了满足a.hello
的要求,您需要将X.hello
的输入作为a.hello
的输入(协方差)的超类并且将X.hello
的输出作为a.hello
的输出(逆变)的子类
想想这是下面的一个具体案例
class A
class A' extends A
class B
class B' extends B
f :: A' -> B
g :: A -> B'
问题是“在表达式y=f(x)
中,我是否可以用g
替换f
,并在相同的情况下仍然进行打字检查
在该表达式中,y
为B
类型,x为A'
在y=f(x)
中,我们知道y
属于B
类型,而x属于A'
g(x)
仍然可以,因为x
属于A'
类型(因此属于A
)
y=g(x)
仍然可以,因为g(x)
属于B'
(因此属于B
)
实际上,最容易看出这一点的方法是y
是B
的一个子类型(即至少实现B
),这意味着你可以使用y
作为B
类型的值。你必须在另一方面做一些心理练习
(我只记得在输入上是一个方向,在输出上是另一个方向,然后尝试一下……如果你仔细想想,就会发现这一点)。在Scala中,可能有同名但参数不同的方法:
class X extends A {
def hello(name:String) = "String"
def hello(name:Any) = "Any"
}
这就是所谓的方法重载,它反映了Java的语义(尽管我的例子很不寻常——通常重载的方法会做大致相同的事情,但参数的组合不同)
您的代码无法编译,因为参数类型需要完全匹配才能进行重写。否则,它会将您的方法解释为具有不同参数类型的新方法
但是,Scala或Java中没有允许重载返回类型的功能-重载只取决于名称和参数类型。使用返回类型重载,除了最简单的情况外,不可能确定在所有情况下使用哪个重载变量:
class X extends A {
def hello: Any = "World"
def hello: String = "Hello"
def doSomething = {
println(hello.toString) // which hello do we call???
}
}
这就是为什么您的第一个示例编译时没有问题——对于您正在实现的方法没有任何歧义
请注意,对于JVM学究——从技术上讲,JVM确实会区分具有不同返回类型的方法。但是,Java和Scala小心地仅将此功能用作优化,并且它不会反映在Java或Scala的语义中。您的代码不会编译,因为参数类型需要完全匹配,重载才能工作.=>您的意思是:“覆盖吗"? => 您的代码无法编译,因为参数类型需要完全匹配才能进行重写。该死的相似的名字。你说得对。我已经更正了。更新:这是可以支持的,但是对于一个很少有用的特性,它会使语言更加复杂。您还可以执行编译器手动执行的相同操作:同时定义defhello(x:Any):Any=…
和overridefhello(x:String):Any=hello(x.asInstanceOf[Any])
。从技术上讲,在Java中,您通常也不能使用细粒度较低的参数重写方法-它显示为重载。
class X extends A {
def hello: Any = "World"
def hello: String = "Hello"
def doSomething = {
println(hello.toString) // which hello do we call???
}
}