有人可以简单地向我解释 Shapeless 库的用途吗?
Scala 具有泛型和继承功能,所以我有点困惑 Shapeless 的用途。
也许一个用例来澄清事情会有所帮助。
有点难以解释,因为 shapeless 具有广泛的特征;我可能会发现“用简单的术语解释变量的用途”更容易。您肯定想从功能概述开始。
从广义上讲,shapeless 是关于使用类型进行编程。在编译时做一些通常在运行时做的事情,精确跟踪列表中每个元素的类型,能够从元组转换为 HLists 到案例类,创建多态函数(相对于方法),等等
典型的使用场景如下:
List
List
转换为HList
HList
使用多态函数映射它,例如规范化值Int
)转换为 0 填充字符串作为参考, anHList
将具有精确的类型,例如Int :: String :: Boolean :: HNil
(是的,这确实是一种类型),其中所有内容都固定下来并且大小固定。因此,您要么需要在编译时确切地知道 HList 中的内容,要么需要类型安全的强制转换。
如果你采用tail
这样的 HList 的 ,你会得到一个String :: Boolean :: HNil
,并且编译时保证 this 的头部是一个String
。在头部添加一个值同样会保留所有涉及的类型。
Shapeless 还带有Generic
类型类,允许您在元组和案例类上使用 HList 操作。
我倾向于使用的其他功能是:
Coproducts
,它允许您静态键入一个值,例如“a String
, Double
or Int
, but nothing else”(很像Either
,但不仅限于两种可能性)
Lenses
,这简化了嵌套案例类的工作。
在您尝试使用类型并委托或打开类型之前,查看 anHList
可能看起来令人费解。看看以下内容:
val myList = 1 :: 2 :: "3" :: fred :: Nil
这里的类型是myList
什么?如果你要检查它,你会发现它的类型是List[Any]
. 这不是很有帮助。如果我尝试使用以下内容PartialFunction[Any]
来解决map
它,则更有帮助的是:
myList.map{
case x: Int => x
case x: String => Int.parseInt(x)
}
在运行时,这可能会抛出 a MatchError
,因为我实际上并没有告诉你什么是类型fred
。它可能是类型Fred
。
HList
如果您未能捕获该列表的一种类型,您可以在编译时立即知道。在上面,如果我在myList = 1 :: 2 :: "3" :: fred :: HNil
访问第三个元素时定义了它,它的类型将是String
,这将在编译时知道。
正如@KevinWright 所说,除了Shapeless 之外,它还有更多功能,但它HList
是该库的定义功能之一。
Shapeless 中的一切都有两个共同点:
首先,它不在 Scala 标准库中,但可以说应该在。因此,询问 Shapeless 的用途有点像询问 Scala 标准库的用途!这是为了一切。这是一个手提袋。
(但它不是一个完全随意的抓包,因为:)
其次,Shapeless 中的所有内容都在编译时提供了增强的检查和安全性。Shapeless 中没有任何东西(我能想到的?)实际上在运行时“做”任何事情。当你的代码被编译时,所有有趣的动作都会发生。目标始终是增加信心,即如果您的代码完全编译,它不会在运行时崩溃或做错事。(因此这个值得注意的俏皮话:https ://twitter.com/mergeconflict/status/304090286659866624 )
在https://stackoverflow.com/a/4443972/86485上有一个很好的介绍类型级编程的全部内容,以及更多资源的链接。