Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 什么';在trait中实现方法的规则是什么?_Scala_Types_Extends_Traits - Fatal编程技术网

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???
  }
}