有人能用简单的语言向我解释一下Shapeless库的用途吗?
Scala具有泛型和继承功能,所以我对Shapeless的用途有点困惑。
也许一个用例来澄清事情会有所帮助。
答案 0 :(得分:47)
有点难以解释,因为无形具有广泛的功能;我可能会发现更容易“用简单的术语解释变量的用途”。你肯定想从feature overview开始。
从广义上讲,无形是关于类型的编程。在编译时做一些事情,通常在运行时完成,保持精确跟踪列表中每个元素的类型,能够从元组转换为HLists到案例类,创建多态函数(而不是方法),等
典型的使用场景如下:
List
List
HList
的类型安全演员
HList
,例如标准化值Int
)转换为0填充字符串作为参考,HList
将具有精确类型,例如Int :: String :: Boolean :: HNil
(是的,真的 是单一类型),其中所有内容都固定下来并且大小合适是固定的。因此,您需要在编译时确切了解将要进入HList的内容,或者您需要类型安全的强制转换。
如果您使用此类HList的tail
,则会获得String :: Boolean :: HNil
,并且编译时保证其头部为String
。将值添加到头部将同样保留所涉及的所有类型。
Shapeless还带有Generic
类型类,允许您对元组和案例类使用HList操作。
我倾向于使用的其他功能是:
Coproducts
,允许您静态输入值,例如“String
,Double
或Int
,但没有别的”(很像Either
,但不仅限于两种可能性)
Lenses
,简化了嵌套案例类的使用。
答案 1 :(得分:32)
在尝试使用类型,委托或切换类型之前,查看HList
可能会让人感到困惑。看看以下内容:
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)
}
在运行时,这可能会抛出MatchError
,因为我实际上并没有告诉你fred
是什么类型。它可以是Fred
类型。
使用HList
,如果您未能捕获该列表的某种类型,则可以在编译时知道。在上面,如果我在访问第3个元素时已经定义了myList = 1 :: 2 :: "3" :: fred :: HNil
,那么它的类型将是String
,这将在编译时知道。
正如@KevinWright所说,除了Shapeless之外,它还有更多,但HList
是该库的定义功能之一。
答案 2 :(得分:20)
Shapeless中的所有东西都有两个共同点:
首先,它不在Scala标准库中,但可以说应该是。因此,询问Shapeless的用途有点像询问Scala标准库是为了什么!这是的一切。这是一个抓包。
(但它不是一个完全随意的抓包,因为:)
其次,Shapeless中的所有内容都在编译时提供了更多的检查和安全 。 Shapeless中没有什么(我能想到的?)在运行时实际上“做”了什么。编译代码时会发生所有有趣的操作。目标始终是增加信心,如果您的代码完全编译,它将不会崩溃或在运行时做错事。 (因此这个值得注意的讽刺:https://twitter.com/mergeconflict/status/304090286659866624)
在https://stackoverflow.com/a/4443972/86485处有一个很好的介绍什么类型级编程,以及更多资源的链接。