有人可以简单地向我解释Shapeless库的用途吗?
Scala具有泛型和继承功能,因此我对Shapeless的用途感到有些困惑。
也许用例来说明问题会有所帮助。
Answers:
很难解释,因为无形状具有多种功能。我可能会发现“以简单的方式解释什么是变量”更为容易。您肯定要从功能概述开始。
广义地说,无形是关于使用类型进行编程。在编译时执行通常在运行时完成的事情,精确跟踪列表中每个元素的类型,能够将元组转换为HList到case类,创建多态函数(与方法相对),等等
典型的使用场景如下:
List
List
转换HList
HList
用多态函数在其上进行映射,例如对值进行归一化Int
)转换为0填充的字符串作为参考,anHList
将具有精确的类型,例如Int :: String :: Boolean :: HNil
(是的,这实际上是单个类型),其中所有内容固定,大小固定。因此,您要么需要在编译时确切地知道将要进入HList的内容,要么需要类型安全的强制转换。
如果tail
使用HList的,则将获得String :: Boolean :: HNil
,并在编译时保证其头将是String
。在值前面加上一个值将类似地保留所有涉及的类型。
Shapeless也随Generic
类型类一起提供,允许您在元组和案例类上使用HList操作。
我倾向于使用的其他功能是:
Coproducts
,这让你静态类型的值作为例如“一个String
,Double
或者Int
,但没有别的”(很像Either
,但不局限于只有两个可能性)
Lenses
,这简化了嵌套案例类的使用。
在HList
尝试使用类型并委派或启用类型之前,看一个似乎有些困惑。看一下以下内容:
val myList = 1 :: 2 :: "3" :: fred :: Nil
这里是什么类型myList
?如果要检查它,您会发现它是type List[Any]
。那不是很有帮助。如果我尝试使用以下内容PartialFunction[Any]
来解决问题,map
则更没有帮助:
myList.map{
case x: Int => x
case x: String => Int.parseInt(x)
}
在运行时,这可能会抛出a,MatchError
因为我实际上没有告诉您什么是类型fred
。它可能是type Fred
。
使用a,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上可以很好地介绍类型级编程的全部内容,并提供指向更多资源的链接。