有人能简单解释一下无形图书馆是干什么用的吗?
Scala 有泛型和继承功能,所以我有点搞不懂 Shapless 是干什么的。
也许用一个用例来澄清事情会有所帮助。
这有点难以解释,因为无形具有广泛的特性; 我可能会发现“用简单的术语解释变量是用来做什么的”更容易一些。你肯定想从 功能概览开始。
广义地说,无形是指使用类型进行编程。在编译时完成通常在运行时完成的工作,精确跟踪列表中每个元素的类型,能够将元组转换为 HList,转换为 case 类,创建多态函数(而不是方法) ,等等。
典型的使用场景是这样的:
List
HList
Int
作为参考,一个 HList将有一个精确的类型,如 Int :: String :: Boolean :: HNil(是的,真正的 是一个单一的类型) ,其中一切都固定下来,大小是固定的。因此,您要么需要在编译时确切地知道将要进入 HList 的内容,要么需要类型安全强制转换。
Int :: String :: Boolean :: HNil
如果获取这样一个 HList 的 tail,就会得到一个 String :: Boolean :: HNil,并且在编译时保证其头部是 String。类似地,在头部预设一个值将保留所有涉及的类型。
tail
String :: Boolean :: HNil
String
Shapless 还附带了 Generic类型类,允许您对元组和 case 类使用 HList 操作。
Generic
我倾向于使用的其他特性是:
Coproducts ,它允许您静态地键入一个值,例如“ a String,Double或 Int,但没有其他值”(非常类似于 Either,但不限于两种可能性)
Coproducts
Double
Either
Lenses ,它简化了使用嵌套案例类的工作。
Lenses
查看 HList可能是一件令人困惑的事情,直到您尝试处理类型并委托或打开类型。请看以下内容:
val myList = 1 :: 2 :: "3" :: fred :: Nil
这里的 myList是什么类型的?如果你检查一下,你会发现它是 List[Any]型的。这可没什么帮助。如果我试着用下面的 PartialFunction[Any]到 map来代替它,那就更没有帮助了:
myList
List[Any]
PartialFunction[Any]
map
myList.map{ case x: Int => x case x: String => Int.parseInt(x) }
在运行时,这可能抛出一个 MatchError,因为我实际上还没有告诉您 fred是什么类型。可能是 Fred型。
MatchError
fred
Fred
使用 HList,您可以在编译时知道是否未能捕获该列表的一种类型。在上面的例子中,如果我在访问第3个元素时定义了 myList = 1 :: 2 :: "3" :: fred :: HNil,那么它的类型应该是 String,这在编译时就会知道。
myList = 1 :: 2 :: "3" :: fred :: HNil
正如@KevinWright 所说,Shapless 不仅仅是这样,而且 HList是该库的一个重要特性。
《无形》里的所有东西都有两个共同点:
首先,它不在 Scala 标准库中,但可以说应该在。因此,询问 Shapless 的用途有点像询问 Scala 标准库的用途!是 谢谢你所做的一切。这是个抢包。
(但这不是一个完全随意的抓包,因为:)
其次,Shapless 中的所有内容都增加了检查和安全 在编译时。《无形》里没有(我能想到的?)实际上在运行时“做”任何事情。编译代码时会发生所有有趣的操作。目标总是增加信心,即如果您的代码编译,它不会崩溃或在运行时做错误的事情。(因此,这个著名的俏皮话: https://twitter.com/mergeconflict/status/304090286659866624“做 Miles Sabin 在运行时存在吗?”)
在 https://stackoverflow.com/a/4443972/86485上有一个关于类型级编程的很好的介绍,以及指向更多资源的链接。