gpt4 book ai didi

Scala:上限 [T <: AnyRef] 不允许返回 [AnyRef]

转载 作者:行者123 更新时间:2023-12-01 22:17:15 26 4
gpt4 key购买 nike

我试图表达以下想法:函数 caseClassFields 应该通过处理案例类返回一个 (String, T) 对数组。我为 T 设置了上限,期望它应该是 AnyRef 的子类型或 AnyRef 本身。

这是一个函数:

def caseClassFields[T <: AnyRef](obj: AnyRef): Array[(String, T)] = {
val metaClass = obj.getClass
metaClass.getDeclaredFields.map {
field => {
field.setAccessible(true)
(field.getName, field.get(obj))
}
}
}

但不幸的是我得到以下错误:

类型Array[(String, AnyRef)] 的表达式不符合预期类型Array[(String, T)]

如何解决这个问题?

最佳答案

用反射做你想做的和保持类型安全是正交的要求。但是shapeless ,一个用于泛型派生的库,可以做你想做的事,同时仍然保证你输入的安全。

这是一个使用 shapeless 来帮助您入门的简短示例。

我们首先定义我们的代数:

sealed trait ValidatableField

case class ValidatableString(value: Boolean)
extends ValidatableField

case class ValidatableInt(value: Boolean) extends ValidatableField

case class ValidatableRecord(fields: List[(String, ValidatableField)])
extends ValidatableField

现在我们定义验证器特征:

trait Validator[T] {
def validate(value: T): ValidatableField
}

trait RecordValidator[T] extends Validator[T] {
def validate(value: T): ValidatableRecord
}

现在让我们为示例定义 IntString 的验证:

implicit val intValidator = new Validator[Int] {
override def validate(t: Int): ValidatableField = ValidatableInt(t > 42)
}

implicit val stringValidator = new Validator[String] {
override def validate(t: String): ValidatableField = ValidatableString(t.length < 42)
}

现在我们为 HList 定义一个通用实现,它将覆盖我们的 ValidatableRecord,它是我们案例类的通用表示:

implicit val hnilEncoder: RecordValidator[HNil] = new RecordValidator[HNil] {
override def validate(value: HNil): ValidatableRecord = ValidatableRecord(Nil)
}

implicit def hlistValidator[K <: Symbol, H, T <: HList](
implicit witness: Witness.Aux[K],
hEncoder: Lazy[Validator[H]],
tEncoder: RecordValidator[T]
): RecordValidator[FieldType[K, H] :: T] = {
val fieldName = witness.value.name
new RecordValidator[::[FieldType[K, H], T]] {
override def validate(value: ::[FieldType[K, H], T]): ValidatableRecord = {
val head = hEncoder.value.validate(value.head)
val tail = tEncoder.validate(value.tail)
ValidatableRecord((fieldName, head) :: tail.fields)
}
}
}

implicit def genericEncoder[A, H <: HList](
implicit generic: LabelledGeneric.Aux[A, H],
hEncoder: Lazy[RecordValidator[H]]): Validator[A] = {
new RecordValidator[A] {
override def validate(value: A): ValidatableRecord =
hEncoder.value.validate(generic.to(value))
}
}

有了这么多代码,我们现在可以验证任何包含 StringInt 字段的案例类,并且为更多原语添加其他验证器是微不足道的:

object Test {
def main(args: Array[String]): Unit = {
case class Foo(s: String, i: Int)
val foo = Foo("hello!", 42)
println(Validator[Foo].validate(foo))
}
}

产量:

ValidatableRecord(List((s,ValidatableString(true)), (i,ValidatableInt(false))))

我知道这可能有点让人不知所措,但是 David Gurnells "Guide To Shapeless"是一个很好的起点。

关于Scala:上限 [T <: AnyRef] 不允许返回 [AnyRef],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44110355/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com