[英]Idiomatic Scala: Semantic difference between <Collection>Like and <Collection> Types?
[英]Scala - Idiomatic way of creating a collection of types
假设我有一个看起来像这样的 ADT
sealed trait TT
case class A(...) extends TT
case class B(...) extends TT
case class C(...) extends TT
// ... lot of others
我有这个函数,它为TT
的子集返回 true 。 假设A
和C
。
def shouldIPublish(tt: TT): Boolean = ???
tt
来自一个我无法真正改变的SortedSet
。 下面是函数shouldIPublish
的调用方式: tts.exists(shouldIPublish)
( tts
是一个SortedSet[TT]
)。 它被擦除。TT
类型进行编译。 如果tt
的实际类型在子集(即A
或C
)中,则返回true
否则返回false
。val shouldIPublishPF: PartialFunction[TT, Unit] = {
case _: A =>
case _: C =>
}
def shouldIPublish(tt: TT): Boolean = shouldIPublishPF.isDefinedAt(tt)
我在这里使用部分函数是因为实际问题有点复杂。 我使用orElse
将几个部分函数组合在一起。
这个解决方案很容易推理,也很简单。 但,
A
和C
。 当向部分函数添加新类型时,我的单元测试应该会失败。也许是最简单的解决方案。 我可以有一个Set
并使用.getClass
获取类。 虽然看起来很丑。
Set(A.getClass, C.getClass)
起初看起来很有希望。 非常地道。
type ShoudIPublish = A :+: C :+: CNil
不幸的是,我不知道如何在ShoudIPublish
测试“包含” ShoudIPublish
。 而且我不知道我们是否可以收集所有类型的列表(这里是A
和C
)。
你有什么建议吗?
类型类看起来像一个解决方案(如果你知道tt
的类型,即在编译时TT
特定子类型)
trait ShouldIPublish[T <: TT]
object ShouldIPublish {
implicit val a: ShouldIPublish[A] = null
implicit val c: ShouldIPublish[C] = null
}
def shouldIPublish[T <: TT : ShouldIPublish](tt: T) = ???
shouldIPublish(A())
// shouldIPublish(B()) // doesn't compile
shouldIPublish(C())
标准类型类是shapeless.ops.coproduct.Inject
type ShoudIPublish = A :+: C :+: CNil
def shouldIPublish[T <: TT : Inject[ShoudIPublish, *]](tt: T) = ???
shouldIPublish(A())
// shouldIPublish(B()) // doesn't compile
shouldIPublish(C())
OOP 风格的解决方案是使用特征(如果您可以修改层次结构)
trait ShouldIPublish
sealed trait TT
case class A() extends TT with ShouldIPublish
case class B() extends TT
case class C() extends TT with ShouldIPublish
def shouldIPublish[T <: TT with ShouldIPublish](tt: T) = ???
shouldIPublish(A())
// shouldIPublish(B()) // doesn't compile
shouldIPublish(C())
当您在编译时不知道TT
特定子类型时,模式匹配解决方案可以在运行时工作
def shouldIPublish(tt: TT) = tt match {
case _: A => println("A")
case _: C => println("C")
}
shouldIPublish(A(): TT)// A
shouldIPublish(B(): TT)// MatchError
shouldIPublish(C(): TT)// C
或者
trait ShouldIPublish
sealed trait TT
case class A() extends TT with ShouldIPublish
case class B() extends TT
case class C() extends TT with ShouldIPublish
def shouldIPublish(tt: TT) = tt match {
case _: ShouldIPublish => println("A or C")
}
shouldIPublish(A(): TT)// A or C
shouldIPublish(B(): TT)// MatchError
shouldIPublish(C(): TT)// A or C
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.