scala - Scala Generics,这 4 个通用版本中的哪个特定于哪个特定问题
问题描述
这四个版本可以编译,但我很好奇我们应该更喜欢一个选项而不是另一个选项的上下文。
// 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])
4
除了我所知道Seq[_]
的代表我不知道该说什么Seq[Any]
最后,我只是想了解更多关于这些工具及其特性的信息,以便更正确地完成工作。
解决方案
// 2
def f[N, S[N] <: Seq[N]](s: S[N])
这里的想法是第一个N
参数和N
中提到的S[N] <: Seq[N]
都是完全独立的参数。他们只是共享同一个名字。
N
in 中提到的S[N]
仅在其 bound 的范围内可见<: Seq[N]
。
N
参数定义中使用的参数(s: S[N])
来自 first N
,因为这是N
参数类型定义中唯一可见的参数。因此,您可以使用任何字母代替N
in 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
used inSeq[N]
与第一个参数相同N
。所以这是一样的N
推荐阅读
- python - 使用 Python Turtle setworldcoordinates() 移动窗口
- html - 如何为 CLS 处理未知尺寸的图像
- excel - PowerQuery - 运行差异列 - 有点像运行总计
- raspberry-pi3 - agl-sota u-boot raspberrypi3 - 卡没有响应电压选择!设备 0:未知设备
- javascript - 是否可以在深度纹理上使用 texSubImage2D?
- visual-studio - 如何将 VisualStudio 2017 连接到特定的 AOS AX2012?
- angular - 取消订阅路由器事件
- macos - 获取mac文件夹中的文件名
- go - 接收器命名一致性
- javascript - 根据另一个列表中对象的属性过滤对象列表