[英]Scala - Idiomatic way of creating a collection of types
Let's says that I have an ADT that look like that假设我有一个看起来像这样的 ADT
sealed trait TT
case class A(...) extends TT
case class B(...) extends TT
case class C(...) extends TT
// ... lot of others
And I have this function that return true for of subset of TT
.我有这个函数,它为TT
的子集返回 true 。 Let's say A
and C
.假设A
和C
。
def shouldIPublish(tt: TT): Boolean = ???
tt
we receive comes from a SortedSet
that I can't really change.我们收到的值tt
来自一个我无法真正改变的SortedSet
。 Here is how the function shouldIPublish
is called : tts.exists(shouldIPublish)
( tts
is a SortedSet[TT]
).下面是函数shouldIPublish
的调用方式: tts.exists(shouldIPublish)
( tts
是一个SortedSet[TT]
)。 It is erased.它被擦除。TT
type.代码应该针对每种TT
类型进行编译。 If the actual type of tt
is in a subset (ie A
or C
) return true
otherwise false
.如果tt
的实际类型在子集(即A
或C
)中,则返回true
否则返回false
。val shouldIPublishPF: PartialFunction[TT, Unit] = {
case _: A =>
case _: C =>
}
def shouldIPublish(tt: TT): Boolean = shouldIPublishPF.isDefinedAt(tt)
I use partial functions here because the actual problem is a bit more complex.我在这里使用部分函数是因为实际问题有点复杂。 I use orElse
to combine several partial functions together.我使用orElse
将几个部分函数组合在一起。
This solution is easy to reason about and simple enough.这个解决方案很容易推理,也很简单。 But,但,
A
and C
.在这种情况下,它将是A
和C
。 My unit test should fail when a new type is added to the partial function.当向部分函数添加新类型时,我的单元测试应该会失败。Maybe the simplest solution.也许是最简单的解决方案。 I could have a Set
and get class with .getClass
.我可以有一个Set
并使用.getClass
获取类。 It seems ugly though.虽然看起来很丑。
Set(A.getClass, C.getClass)
Looked quite promising at first.起初看起来很有希望。 Very idiomatic.非常地道。
type ShoudIPublish = A :+: C :+: CNil
Unfortunately, I don't see how to test that a type is "contained" in ShoudIPublish
.不幸的是,我不知道如何在ShoudIPublish
测试“包含” ShoudIPublish
。 And I don't know if we can collect the list of all types (here A
and C
).而且我不知道我们是否可以收集所有类型的列表(这里是A
和C
)。
Do you have any suggestion?你有什么建议吗?
Type class looks like a solution (if you know the type of tt
ie specific subtype of TT
at compile time)类型类看起来像一个解决方案(如果你知道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())
Standard type class is shapeless.ops.coproduct.Inject
标准类型类是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-style solution would be to use a trait (if you can modify the hierarchy) 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())
Pattern-matching solution can work at runtime when you don't know specific subtype of TT
at compile time当您在编译时不知道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
or或者
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.