2012-05-15 64 views
23

我相信人们可以将协变量(至少对于对象)定义为'使用更窄(子)类型的值代替更宽(超)类型'的值的能力,并且该反向是准确的与此相反。为什么函数[-A1,...,+ B]不允许任何超类型作为参数?

显然,Scala函数是函数[-A1,...,+ B]的实例,用于逆变参数类型A1等和协变返回类型B.虽然这对函数的子类型很方便,但不应该上面的定义意味着我可以传递任何超类型作为参数?

请告知我误会的地方。

回答

56

协方差和逆变是不是参数品质的品质。 (它们是依赖于参数的质量,但他们做关于类的语句。)

所以,Function1[-A,+B]意味着功能,它利用A超能为原有功能一个子类进行查看。

让我们来看看这在实践中:

class A 
class B extends A 
val printB: B => Unit = { b => println("Blah blah") } 
val printA: A => Unit = { a => println("Blah blah blah") } 

现在假设你需要知道如何打印B功能:

def needsB(f: B => Unit, b: B) = f(b) 

你可以通过在printB。但你也可以通过printA,因为它也知道如何打印B s(和更多!),就好像A => UnitB => Unit的子类。这正是反转意味着什么。这并不意味着您可以将Option[Double]转换为printB,并且只能得到编译时错误!

(协方差是另一种情况下:如果M[B] <: M[A]B <: A

+0

谢谢你,那很清楚。尝试(重新)定义:'co/contra-variance是指示类型之间的子类型关系的属性,受其组件类型之间相同关系的性质影响。摘要,我知道,但我更喜欢有一个没有例子的定义(尽管你非常有帮助)。 – bjt38

+0

感谢-A,你能解释为什么在Function1 [+ A,+ B] + B + – liango

+0

@liango - 一个例子的解释:如果你返回一个String,你肯定会返回一个Object,所以'。 .. => String'必须是'... => Object'的子类。这就是'+ B'表示的意思。 –

4

这里有两个独立的想法。一种是使用子类型来允许将更具体的参数传递给函数(称为包含)。另一个是如何检查函数本身的子类型。

对于类型检查函数的参数,您只需检查给定的参数是否为已声明参数类型的子类型。结果也必须是声明类型的子类型。这是你实际检查子类型的地方。

的禁忌症/参数&结果唯一因素,当你想检查一个给定功能型是否是另一种功能类型的子类型的协方。因此,如果参数的类型为Function[A1, ... ,B],那么参数必须是函数类型Function[C1, ..., D],其中A1 <: C1 ...D <: B

此推理不是特定于Scala,适用于其他具有子类型的静态类型语言。

-1

协变装置从更宽的(超)转化成更窄的(子)。例如,我们有两个班:一个是动物(超级),另一个是使用协变的猫,我们可以将动物转化为猫。

反变形只是协变的相反,这意味着猫对动物。

不能指定无法转换。

18

这个问题很古老,但我认为一个更清晰的解释是引用Liskov替代原则:关于超类的所有事情都应该对其所有子类都是真实的。你应该可以用SubFoo做一些你可以用Foo做的事情,或许更多。

假设我们有印花布<:猫<:动物和赫斯基<:狗<:动物。我们来看一下Function[Cat, Dog]。什么陈述是真的关于这个?有两种:

(1)您可以在任何猫(所以猫的任何子类)通过

(2)你可以调用的返回值的任何狗方法

所以确实Function[Calico, Dog] <: Function[Cat, Dog]才有意义?不,超类的语句对于子类是不正确的,即语句(1)。你不能将任何猫只传递给只能使用印花布猫的功能。

但是Function[Animal, Dog] <: Function[Cat, Dog]有道理吗?是的,关于超类的所有陈述对于子类都是真实的。我仍然可以传入任何猫 - 事实上我可以做的更多,我可以传入任何动物 - 我可以调用所有狗的方法对返回的值。

所以A <: B意味着Function[B, _] <: Function[A, _]

现在,确实Function[Cat, Husky] <: Function[Cat, Dog]有意义吗?是的,关于超类的所有陈述对于子类都是真实的;我仍然可以传入一个Cat,并且仍然可以调用所有Dog方法的返回值 - 实际上我可以做的更多,我可以调用返回值上的所有Husky方法。

但是Function[Cat, Animal] <: Function[Cat, Dog]有意义吗?不,超类的语句对于子类是不正确的,即语句(2)。我不能在返回的值上调用Dog上的所有可用方法,只能使用Animal上可用的方法。

因此,通过Function[Animal, Husky],我可以做所有我能做的事情:Function[Cat, Dog]:我可以传入任何Cat,并且可以调用返回值上的所有Dog方法。而且我可以做得更多:我可以传入其他动物,并且我可以调用赫斯基上可用的狗上不可用的方法。所以它是有道理的:Function[Animal, Husky] <: Function[Cat, Dog]。第一个类型参数可以用一个超类替换,第二个类可以用一个子类替换。

+0

如何通过编程方式检查<您提供的示例? –

相关问题