Scala函数方差和覆盖 [英] Scala Function Variance and Overriding
问题描述
我在解决重载时方法的方差方面遇到一些问题。
I'm having a little problem understanding variance of methods when overloading.
虽然返回类型中的协方差可以完美地起作用
While this perfectly works due to covariance in the return type
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
}
即使函数在
参数类型中是逆变的,也会失败。
this one fails even though functions are contravariant in their parameter types.
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
}
我在这里出错了什么?任何指针?
What am I getting wrong here? Any pointers?
问候,
raichoo
Regards, raichoo
推荐答案
这里有两件事:
- 一个函数和一个方法 不是一回事
- 方法不是多态的参数'的类型
您的测试人员
方法是一种方法,不是a Function1
。可以使用下划线语法将其提升为函数:
Your tester
method is a method, not a Function1
. It can be lifted into a function using the underscore syntax:
val f = (new FooTest[String]).tester _ // Fasel => Bla
此函数在其输入类型中将是反变量。 (值得一提的是,函数无法参数化并且还值得说我必须有一个 Foo
或<$ c $的实例c> FooTest 以获取 tester
方法的函数对象。这当然是从第一次观察开始的!)
This function will be contra-variant in its input type. (It's worth saying, however, that functions cannot be parameterized and also worth saying that I had to have an instance of Foo
or FooTest
in order to get a function object for the tester
method. This of course follows from the first observation!)
函数是一个对象,它不能被覆盖因为没有意义。方法可以被覆盖。但是,正如我上面所说,覆盖在方法的参数类型中不是多态的。例如:
A function is an object, it cannot be overridden as that makes no sense. Methods can be overridden. However, as I say above, the overriding is not polymorphic in the method's parameter types. So for example:
class A {
def foo(a : Any) = println("A: " + a)
}
class B extends A {
override def foo(s : String) = println("B " + s) //will not compile!
}
上面示例中的两个方法是两个独立的方法:动态调度仅起作用在方法目标(即调用它的对象)上。
The two methods in my example above are two separate methods: dynamic dispatch works only on the method target (i.e. the object on which it is being called).
在上面的示例中,如果删除覆盖
声明,代码将编译。如果您运行以下内容:
In the above, example, if you remove the override
declaration, the code will compile. If you run the following:
(new B).foo(1) //prints A 1
(new B).foo("s") //prints B s
这是因为,尽管两种方法被称为 foo
,它们是完全不同的方法(即我重载 foo
,而不是重写它)。最好理解为方法的参数'(包括它们的类型)构成该方法的唯一名称的一部分。一种方法只有在具有完全相同的名称时才会覆盖另一种方法。
This is because, although both methods are called foo
, they are completely different methods (i.e. I have overloaded foo
, not overridden it). It's best understood as being that a method's arguments' (incl their types) form part of that method's unique name. One method overrides another only if they have exactly the same name.
基本上你混淆了问题中的两个单独和不相关的东西为了清楚起见,我将放下来:
Essentially you have confused what are two separate and un-related things in your question, which I will put down for clarity:
-
Function1
上的方差注释定义一个函数作为另一个函数的子类型意味着什么(因此可赋值到给定类型的引用)。 - 可以在子类上重写方法语言规范概述了何时发生此类重写的规则。
- The variance annotations on
Function1
define what it means for one function to be a subtype of another (and hence assignable to a reference of a given type). - Methods can be overridden on subclasses and the language specification outlines rules for when such overriding takes place.
这篇关于Scala函数方差和覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!