这四个版本都可以编译,但我很好奇我们应该更喜欢一个选项而不是另一个选项的上下文。
// 1
def f[N, S <: Seq[N]](s: S)
// 2
def f[N, S[N] <: Seq[N]](s: S[N])
使用1
而不是2
时它们非常相似
2
强加 S
将 N
作为通用参数,与 1
相同,但是它们之间有什么区别两个?
然后我们有更多常规设置。
// 3
def f[N, S[X] <: Seq[X]](s: S[N])
// 3.a
def f[N, S[X] <: Seq[X]](s: S[N]): S[Int]
根据我的理解,3
授权提取通用容器类型以便稍后重用,并获得类似3.a
的内容。
但是未声明的 X 泛型参数的含义是什么,我想这是一种声明特殊内容的方法,但我不明白。
// 4
def f[N, S[X] <: Seq[_]](s: S[N])
除了我所知道的 Seq[_]
代表 Seq[Any]
以外,我不知道该对 4
说什么
最后,我只是想了解有关这些工具及其特殊性的更多信息,以便更正确地完成工作。
最佳答案
// 2
def f[N, S[N] <: Seq[N]](s: S[N])
这里的想法是第一个 N
参数和N
S[N] <: Seq[N]
中提到是完全独立的参数。他们只是共用同一个名字。
N
S[N]
中提到仅在其绑定(bind)的 <: Seq[N]
范围内可见。
N
用于参数定义(s: S[N])
来自第一个 N
因为这是唯一的N
参数对于参数类型定义可见。所以而不是 N
在S[N] <: Seq[N]
您可以使用任何字母,这不会以任何方式影响您的参数类型。
// 4
def f[N, S[X] <: Seq[_]](s: S[N])
这里你刚刚忽略了X
参数。
编辑:正如@alexey-romanov 在评论中提到的那样。 S[X] <: Seq[X]
之间有区别和S[X] <: Seq[_]
下面是一个显示差异的示例:
def f1[N, S[X] <: Seq[X]](s: S[N]) = ""
def f2[N, S[X] <: Seq[_]](s: S[N]) = ""
type Foo[A] = Seq[Int]
val foo: Foo[String] = Seq(2,3)
//f1(foo) -- compilation error
f2(foo)
这里的问题是,由于类型构造函数是一种“类型上的函数”,我们可以定义这样的“函数”,接受一种类型作为参数,但返回由与类型构造函数中使用的参数无关的另一个参数参数化的类型。 (参见类型Foo
)
通过foo
val 为 f2
很好,因为 X
被推断为 String 和 Foo[String]
是 Seq[Int]
的“子类型”(实际上它们是相等的) ,但是当我们通过foo
时至f1
X
仍然是String
但是Foo[String]
不是 Seq[String]
的“子类型” (因为 Foo[String]==Seq[Int] 不是 Seq[String] 的子类型)
// 1
def f[N, S <: Seq[N]](s: S)
你在这里说过N
用于Seq[N]
与第一个参数 N
相同。所以这是一样的N
关于Scala 泛型,这 4 个泛型版本中的哪一个特定于哪个特定问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53359958/