Inheritance Scala函数的方差和重写
当重载时,我在理解方法的变化方面有点问题 由于返回类型中的协方差,这一点非常有效Inheritance Scala函数的方差和重写,inheritance,scala,overriding,variance,Inheritance,Scala,Overriding,Variance,当重载时,我在理解方法的变化方面有点问题 由于返回类型中的协方差,这一点非常有效 class Bla class Fasel extends Bla trait Test[A] { def tester(): Bla = new Bla } class FooTest[A](a: A) extends Test[A] { override def tester(): Fasel = new Fasel }
class Bla
class Fasel extends Bla
trait Test[A] {
def tester(): Bla = new Bla
}
class FooTest[A](a: A) extends Test[A] {
override def tester(): Fasel = new Fasel
}
即使函数在其内部是相反的,这个函数也会失败
参数类型
class Bla
class Fasel extends Bla
trait Test[A] {
def tester(a: Fasel): Bla = new Bla
}
class FooTest[A](a: A) extends Test[A] {
override def tester(a: Bla): Fasel = new Fasel
}
我这里出了什么错?有什么建议吗
问候,,
raichoo在您的第二个示例中,
Test
中的tester()
的签名声明了一个Fasel
参数,但是使用FooTest
tester()
的覆盖签名声明的参数是Bla
。由于Fasel
是其extend
s层次结构的Bla
的一个子类型,这可能是错误的。这里有两件事:
测试仪
方法是一种方法,而不是功能1
。可以使用下划线语法将其提升到函数中:
val f = (new FooTest[String]).tester _ // Fasel => Bla
此函数的输入类型将与之相反。(但是,值得一提的是,函数不能参数化,也值得一提的是,我必须有一个Foo
或FooTest
的实例,才能为tester
方法获取函数对象。这当然是从第一次观察中得出的!)
函数是一个对象,它不能被重写,因为这毫无意义。方法可以被重写。但是,正如我上面所说的,重写在方法的参数类型中不是多态的。例如:
class A {
def foo(a : Any) = println("A: " + a)
}
class B extends A {
override def foo(s : String) = println("B " + s) //will not compile!
}
上面示例中的两个方法是两个独立的方法:动态分派仅对方法目标(即调用它的对象)起作用
在上面的示例中,如果删除覆盖
声明,代码将编译。如果运行以下命令:
(new B).foo(1) //prints A 1
(new B).foo("s") //prints B s
这是因为,尽管这两种方法都被称为foo
,但它们是完全不同的方法(即,我重载了foo
,而不是重写它)。最好理解为方法的参数(包括其类型)构成该方法唯一名称的一部分。一个方法只有在它们具有完全相同的名称时才重写另一个方法
基本上,你已经混淆了你问题中的两个独立和不相关的事物,为了清楚起见,我将把它们记下来:
上的方差注释定义了一个函数作为另一个函数的子类型(因此可分配给给定类型的引用)的含义Function1
- 方法可以在子类上重写,并且语言规范概述了此类重写发生的规则
class FooTest[A] extends Test[A] {
override def test(a: Fasel) : Fasel = test(a.asInstanceOf[Bla])
def test(a: Bla) : Fasel = new Fasel
}
您可以做的是使中提供的类型参数逆变,它仅显示在逆变位置(简化,显示为参数类型,而不是结果类型),但它有很大不同:
trait Test[-A] {
// note the - before A.
// You might want to constraint with -A >: Fasel
def tester(a: A) : Bla = new Bla
}
class FooTest extends Test[Bla] {
override def tester(a: Bla): Fasel = new Fasel
}
val testOfBla: Test[Bla] = new FooTest
val testOfFasel: Test[Fasel] = testOfBla
// you can assign a Test[Bla] to a test[Fasel] because of the -A
规范的相关片段: 方法类型 方法类型在内部表示为
(Ps)U
,其中(Ps)
是一些n的参数名称和类型的序列(p1:T1,…,pn:Tn)
≥0
和U
是(值或方法)类型。此类型表示命名方法,这些方法采用类型为T1,…,Tn
的名为p1,…,pn
的参数,并返回类型为U
的结果
方法类型不作为值类型存在。如果方法名用作值,则其类型将隐式转换为相应的函数类型(§6.26)
覆盖
类C
的成员M
与C
基类的非私有成员M′
匹配(§5.1.3),称其覆盖该成员。在这种情况下,覆盖成员M
的约束必须包含(§3.5.2)覆盖成员M′
的约束
合规性
如果Ti≡ Ti′
对于i=1,…,n
和U
符合U′
,则方法类型(p1:T1,…,pn:Tn)U
符合(p1′:T1′,,pn′:Tn′)U′
包含
类类型C
的某个复合类型中的声明或定义包含了某个复合类型或类类型C′
中相同名称的另一个声明,前提是满足以下条件之一
- 定义类型为T的名称x的值声明或定义包含定义类型为
的T′
的值或方法声明,前提是x
T在scala参考中哪里可以阅读?为了完整性:)明白了:3.3.1方法类型谢谢:)我添加了一个关于方法/函数比较的SO问题的链接。此外,关于方法重写的部分是字节码定义的一部分(即类文件格式规范)。虽然我希望Scala语言规范详细说明Scala方法是如何“提升”为字节码方法的,但你没有抓住要点。函数的输入参数是反变的。因此OP对方法重写和函数变化之间的区别感到困惑