scala-泛型中的任意vs下划线
Scala中的以下泛型定义有什么不同:scala-泛型中的任意vs下划线,scala,generics,covariance,any,existential-type,Scala,Generics,Covariance,Any,Existential Type,Scala中的以下泛型定义有什么不同: class Foo[T <: List[_]] class Foo[T当代码不需要知道类型是什么或约束它时,前者是存在类型的简写: class Foo[T <: List[Z forSome { type Z }]] 代码太长了,读不下去了,我想我应该接受它,而不是张贴评论。抱歉,如果你想TL,这个过程会很长,跳过到最后。 正如Randall Schulz所说,这里的是存在主义类型的简写 class Foo[T <: List[_]]
class Foo[T <: List[_]]
class Foo[T当代码不需要知道类型是什么或约束它时,前者是存在类型的简写:
class Foo[T <: List[Z forSome { type Z }]]
代码太长了,读不下去了,我想我应该接受它,而不是张贴评论。抱歉,如果你想TL,这个过程会很长,跳过到最后。
正如Randall Schulz所说,这里的
是存在主义类型的简写
class Foo[T <: List[_]]
这个类是泛型的(注意它也是不变的),但是我们可以看到hello
实际上没有使用类型参数(与getName
不同),因此,如果我得到一个Greets
的实例,我应该总是能够调用它,无论T
是什么。如果我想定义一个方法,它接受一个Greets
实例并只调用它的hello
方法,我可以尝试以下方法:
def sayHi1( g: Greets[T] ) { g.hello() } // Does not compile
毫无疑问,这不会编译,因为T
在这里不知从何而来
那么,让我们将该方法设置为泛型:
def sayHi2[T]( g: Greets[T] ) { g.hello() }
sayHi2( Greets("John"))
sayHi2( Greets('Jack))
很好,这很有效。我们也可以在这里使用存在主义:
def sayHi3( g: Greets[_] ) { g.hello() }
sayHi3( Greets("John"))
sayHi3( Greets('Jack))
总之,在类型参数(如sayHi2
)上使用存在式(如sayHi3
)并没有什么真正的好处
但是,如果Greets
本身作为另一个泛型类的类型参数出现,则会发生变化。例如,我们希望在列表中存储Greets
(使用不同的T
)的多个实例。让我们尝试一下:
val greets1: Greets[String] = Greets("John")
val greets2: Greets[Symbol] = Greets('Jack)
val greetsList1: List[Greets[Any]] = List( greets1, greets2 ) // Does not compile
最后一行没有编译,因为问候语
是不变的,所以问候语[String]
和问候语[Symbol]
不能被视为问候语[Any]
,即使字符串和符号
都扩展了Any
好的,让我们试着用一个存在主义符号,使用速记符号\uu
:
val greetsList2: List[Greets[_]] = List( greets1, greets2 ) // Compiles fine, yeah
这可以很好地编译,您可以按预期执行以下操作:
greetsSet foreach (_.hello)
现在,请记住,我们首先遇到类型检查问题的原因是因为Greets
是不变的。如果将它转换为协变类(class Greets[+T]
),那么一切都会在框中进行,我们就永远不需要存在
总之,存在主义对于处理泛型不变类很有用,但是如果泛型类不需要将自身作为另一个泛型类的类型参数出现,那么可能不需要存在主义,只需向方法中添加一个类型参数就可以了
现在回到(我终于知道了!)你的具体问题,关于
class Foo[T <: List[_]]
所以在这种情况下,使用任何一种符号都只是风格问题
但是,如果将列表
替换为集
,情况会发生变化:
class Foo[T <: Set[_]]
当你解释什么是存在主义时,我认为问题不是存在主义一般是什么,而是T[\u]
(这是存在主义用法的特殊情况)和T[any]之间有没有实际的可观察的区别
?当然有。我提到的博客有一个很好的例子。我希望你的回答能提到协方差对于T[\u]
和T[Any]
之间的区别是多么重要,因为这是问题的核心“为什么要在T[Any]上使用T[\u]
”此外,肖恩·康诺利在他的问题中明确提到了List[\u]
。鉴于List
实际上是协变的,人们可能想知道在这种情况下List[\u]
和List[Any]之间是否真的有区别
。如果T是协变的,并且它的类型参数有Any
作为它的上界,那么T[\u]
和T[Any]
之间似乎没有任何区别。但是,如果你有T[+A@Jesper Nordenberg:实际上在scala 2.8之前,这个推断是有效的,它被“破坏了”在scala 2.8中。事实上,这是故意的,因为显然这与类型系统的其余部分玩得不好,而且不一致(虽然我记不清细节)。将类型限制为No,class Foo[T Doh,我真傻!谢谢,我已经解决了这个问题。有趣的是,我的第一个想法是查看David R MacIver()这正是关于存在主义的速记,并警告了他们的非直觉的去糖化。问题是他自己似乎弄错了。事实上,在他的文章发表后不久,去糖化的方式发生了变化(在scala 2.7.1中,请参见。我想这一变化也造成了混乱。好吧,存在类型语法的含义很容易混淆。至少当前的desugaring是最符合逻辑的语法。最后一个]
放在class Foo[T是的,最后一个]
应该是class Foo[T]
def sayHi3( g: Greets[_] ) { g.hello() }
sayHi3( Greets("John"))
sayHi3( Greets('Jack))
val greets1: Greets[String] = Greets("John")
val greets2: Greets[Symbol] = Greets('Jack)
val greetsList1: List[Greets[Any]] = List( greets1, greets2 ) // Does not compile
val greetsList2: List[Greets[_]] = List( greets1, greets2 ) // Compiles fine, yeah
greetsSet foreach (_.hello)
class Foo[T <: List[_]]
class Foo[T <: List[Any]]
class Foo[T <: Set[_]]
class Foo[T <: Set[Any]]