我最近正在研究猫库,我遇到过这个名为NonEmptyList的类。
在阅读了api之后,我不禁想知道是什么让猫作者创建了一个新类,而不是利用内置的东西(::)并使用类型类扩展它。它甚至没有在cat github页面中列出,所以我来这里询问它。也许是因为cons是List的子类型? (虽然我不知道它的含义)
::和NEL有什么区别?为什么猫作者必须编写NEL而不是使用::?
答案 0 :(得分:3)
NonEmptyList
List
未延伸到::
的主要原因是开发者体验包含API中的假设。
首先,请注意List
具有可能误导的所有方法List
,并且使用更强大的假设设计更好的API变得更加困难。此外,::
没有任何直接返回// NonEmptyList usage is intuitive and types fit together nicely
val nonEmpty: NonEmptyList[Int] = NonEmptyList.of(1, 2, 3)
val biggerNonEmpty: NonEmptyList[Int] = 0 :: nonEmpty
val nonEmptyMapped: NonEmptyList[Int] = nonEmpty.map(_ * 2)
// :: has lots of problems
// PROBLEM: we can't easily instantiate ::
val cons: ::[Int] = 1 :: 2 :: 3 :: Nil // type mismatch; found: List[Int]; required: ::[Int]
val cons: ::[Int] = new ::[Int](1, ::(2, ::(3, Nil)))
// PROBLEM: adding new element to Cons returns List
val biggerCons: ::[Int] = 0 :: cons // type mismatch; found: List[Int]; required: ::[Int]
// PROBLEM: ::.map returns List
val consMapped : ::[Int] = cons.map(_ * 2) // type mismatch; found: List[Int]; required: ::[Int]
的方法,这意味着开发人员需要手动维护非空抽象。
让我向您展示一个显示我在实践中的意思的例子:
NonEmptyList
请注意,List
包含返回filter
的方法,即filterNot
,collect
和NonEmptyList
。为什么?因为通过::
过滤可能意味着您过滤掉所有元素,列表可能变为空元素。
这使得整个非空抽象如此强大。通过正确使用函数输入和输出类型,您可以编码有关API的假设。 ()
没有提供这种抽象。