【发布时间】:2021-06-07 17:07:47
【问题描述】:
我有一个表示一个容器和两个案例类的枚举:
enum Container[+A]:
case Value(value: A)
case Default(default: A)
def get: A = this match
case Value(value) => value
case Default(default) => default
case class PersonTemplate(name: Container[String], age: Container[Int], enabled: Container[Boolean])
case class Person(name: String, age: Int, enabled: Boolean)
我想在 Scala 3 中编写一个通用函数,将所有案例类(如 PersonTemplate)转换为对应的类(如 Person),类似于:
def extract[I <: Product, O <: Product](input: I): O = ???
val initial = PersonTemplate(Value("John"), Default(12), Default(true))
val final = extract[PersonTemplate, Person](initial)
// Result: Person("John", 12, true)
我尝试了几种方法,但没有一个是成功的,主要是因为我不明白如何使用 Scala 3 Tuple 这在我看来与 Scala 2 Shapeless' HList 不同(即使在 shapeless 我也是不太好)。
我的总体方法是:
- 在元组中转换案例类。为此我找到了
Tuple.fromProductTyped - 将每个元素限制为
Container[_]。我发现Tuple.IsMappedBy保证元组具有正确的形状和Tuple.InverseMap似乎提取容器内的类型。不过,我不确定将这段代码放在哪里。 - 对调用
Container.get的每个值应用(poly?)函数。由于我在网上找到的一点点,我最终使用了很多.asInstanceOf,但我觉得它并不合适。 - 使用
summon[Mirror.Of[O]].fromProduct(output)将生成的Tuple转换为输出类型
为了完整起见,这是我尝试的最后一个代码,当然不起作用:
def resolve[I <: Product: Mirror.ProductOf, O: Mirror.ProductOf](input: I): O =
val processed =
Tuple
.fromProductTyped(input)
.map { [T] => (value: T) => ??? }
summon[Mirror.Of[O]].fromProduct(processed)
type ExtractG = [G] =>> G match {
case Container[a] => a
}
def process[I <: Tuple, O <: Tuple](input: I)(using Tuple.IsMappedBy[Container][I]): O =
input.map { [A] => (a: A) =>
a.asInstanceOf[Container[_]].get.asInstanceOf[ExtractG[A]]
}.asInstanceOf[O]
【问题讨论】:
标签: scala generics scala-3 generic-derivation match-types