我一直在嘗試創建一個函式,該函式在任何案例類上都有一些變化,但無法弄清楚如何在非具體泛型型別上實作它,我做錯了什么?
請注意,我無法更改傳遞給此函式的原始案例類 ** 編輯 ** 忘記提及我使用的是 2.13 之前的 scala,并且更喜歡不依賴外部庫的解決方案。
def caseClassToArray[A](something: A) = {
classOf[A]
.getDeclaredFields
.map { f: Field =>
f.setAccessible(true)
val res = (f.getName, f.get(something))
f.setAccessible(false)
res
}
}
uj5u.com熱心網友回復:
如果您正在尋找一種進行反思的方法,@Silvio 的答案很好。
但是,要獲得相同的輸出,您應該依賴庫提供的標準方法,而不是使用反射:
def caseClassToArray[A <: Product](instance: A): Array[(String, Any)] = {
a.productElementNames.zipWith(a.productIterator)
}
請參閱https://www.scala-lang.org/api/current/scala/Product.html(所有案例類都繼承自Product)。
uj5u.com熱心網友回復:
Scala 和 Java 一樣,在運行時擦除泛型型別。因此,如果您想在運行時使用泛型型別做某事A,您需要采用隱式ClassTag引數。
import scala.reflect._
import java.lang.reflect._
def caseClassToArray[A](something: A)(implicit cls: ClassTag[A]) = {
cls.runtimeClass // <-- Instead of classOf[A]
.getDeclaredFields
.map { f: Field =>
f.setAccessible(true)
val res = (f.getName, f.get(something))
f.setAccessible(false)
res
}
}
在 Scala 3 中,這看起來像
def caseClassToArray[A](something: A)(using cls: ClassTag[A]) = {
...
}
uj5u.com熱心網友回復:
鑒于評論中討論的內容,似乎最好的解決方案是型別類并使用Diff Shapeless來派生案例類。
第一步是定義型別類。
trait Diff[A] {
def diff(a1: A, a2: A): A
}
您可能需要針對您的確切用例調整定義。
下一步是提供對基本標準型別的支持,如Int, String,List[A]為任何A具有Diff等
object Diff {
implicit final val IntDiff: Diff[Int] =
new Diff[Int] {
override def diff(i1: Int, i2: Int): Int =
i1 - i2
}
...
}
您可能還想像
implicitNotFound任何其他型別類一樣添加擴展方法、錯誤訊息和所有內容。
這些東西超出了這個答案的范圍。
下一步是使用ShapelessHList為所有元素型別都有Diff關聯的任何物件歸納派生一個實體。
import shapeless.{:: => :!:, HList, HNil}
sealed trait ReprDiff[R <: HList] extends Diff[R]
object ReprDiff {
implicit final val HNilReprDiff: ReprDiff[HNil] =
new ReprDiff[HNil] {
override final def diff(nil1: HNil, nil2: HNil): HNil = HNil
}
implicit def HConsReprDiff[H, T <: HList](
implicit ev: Diff[H], tailReprDiff: ReprDiff[T]
): ReprDiff[H :!: T] = new ReprDiff[H :!: T] {
override final def diff(hlist1: H :!: T, hlist2: H :!: T): H :!: T = {
val headDiff = ev.diff(hlist1.head, hlist2.head)
val tailDiff = tailReprDiff.diff(hlist1.tail, hlist2.tail)
headDiff :: tailDiff
}
}
}
最后,使用無形 Generic魔法,我們可以為任何存在其HList表示實體的案例類提供一個實體。
import shapeless.Generic
sealed trait DerivedDiff[P <: Product] extends Diff[P]
object DerivedDiff {
implicit def instance[P <: Product, R <: HList](
implicit gen: Generic.Aux[P, R], ev: ReprDiff[R]
): DerivedDiff[P] = new DerivedDiff[P] {
override final def diff(p1: P, p2: P): P =
gen.from(ev.diff(gen.to(p1), gen.to(p2)))
}
}
gen.to將案例類的任何實體P轉換為HList表示它的實體。
gen.from將一個匹配的實體HList變成一個P
Now, all we need is a way to let our users derive the instance for their case classes as long as all fields have a Diff associated with them.
I personally prefer the semiauto approach:
// Somewhere, like in the companion object of Diff
def derive[P <: Product](implicit ev: Deriving.DerivedDiff[P]): ev.type = ev
With all that, you can just use it like this:
final case class Foo(a: Int, b: Int)
object Foo {
implicit final val FooDiff: Diff[Foo] =
Diff.derive[Foo]
}
Congratulations, you now can diff two Foo instances:
val foo1 = Foo(1, 3)
val foo2 = Foo(0, 5)
val diff = Diff.diff(foo1, foo2)
// res: Foo = Foo(1, -2)
In this example we added an auxiliary method
diffin theDiffcompanion object; you may provide any other API to call thediffoperation.
You can see the code running here.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/437866.html
