scala-泛型中的任意vs下划线

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[_]]

Scala中的以下泛型定义有什么不同:

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]]