case class Person(name。String。
override val age: Int,
覆寫值地址。String, override val age: Int, override val address: String
) extends Details(age, address)
class Details(val age: Int, val address: String)。
val person = Person("Alex"/span>, 33, "Europe")
val details = person.asInstanceOf[Details] /?
println(details) //I want only Details class fields
我有這2個類。實際上,這兩個類都有很多的欄位。在某個地方,我只需要超級類的欄位,從Person類中抽取。
有什么好方法可以只獲得超類的值,而不是逐個欄位地映射它們?
uj5u.com熱心網友回復:
如果我正確地理解了你的問題,那么你可能是在問我java的運行時多型性或動態方法調度。 如果是這樣,你可能要同時創建類和非案例類
class Details( val age。Int, val address: String)。
class Person(name: String。
override val age: Int,
覆寫值地址。String, override val age: Int, override val address: String
) extends Details(age, address) {
現在創建人的物件和對超類的參考(Details)
val detail: Details = new Person("Alex"/span>, 33, "Europe")
println(detail.address)
println(detail.age)
這樣,你將能夠得到唯一的地址和年齡
另一種方法是,為什么我們不能把Details創建為一個單獨的物體,比如:
case class Details( age: Int, address: String)。
case class Person(name: String,
細節。詳情
)
val detail = Person("Alex", Details(10,"Europe") )
輸出:
println(detail.details)
Details(10, Europe)
uj5u.com熱心網友回復:
我將發布一個利用scala宏系統的解決方案(舊的那種,不是Scala 3.0引入的最新的)。對你來說,這可能是一個過剩的方案......
BTW,如果你想讓你的系統變得更強大,那么你就必須要有一個宏系統。
BTW,如果你只想訪問父類的值(例如獲取鍵、值對),你可以:
因此,我嘗試一步一步地解決每一個點。 首先,我們要把宏定義寫成:
object Macros{
def accessors[T](element : T)。String = macro MacrosImpl.accessors[T].
}
object MacrosImpl{
def accessors[T: c。 WeakTypeTag](c: whiteebox.Context): c.Expr[String] = ...
}
對于第一點,我們可以使用c.universe來利用反射宏編程API:
importc.universe._
val weakType = weakTypeTag[T] //thanks to the WeakTypeTag typeclass[/span
val parents = weakType.tpe.baseClasses
對于第二點,我們可以遍歷父類,然后只取公有訪問器:
val accessors = parents
.map(weakType.tpe.baseType(_))
.flatMap(_.members)
.filter(_.isPublic)
.filter(_.isMethod)
.map(_.asMethod)
.filter(_.isAccessor)
.toSet
因此,例如,如果我們寫Macros.accessors[Details](person),accessors將得到age和address。
為了取值,我們可以利用準繩來進行。所以,首先我們只取值的名字:
val names = accessors
.map(_.fullName)
.map(_.split("."/span>))
.map(_.reverse.head)
然后我們把它們轉換成一個TermName:
val terms = names.map(TermName(_)
最后,我們將每個術語轉換為一個包含val name和其值的key value tuple:
val accessorValues = terms
.map(name => c.Expr[(String, Any)](q" (${name. toString}, ${element}.${name})")
.toSeq
最后一步是將Seq[Expr[(String, Any)]轉換成Expr[Seq[(String, Any)]。要做到這一點,可以利用遞回、reify和splicing運算式:
def seqToExprs(seq: Seq[Expr[(String, Any)]]: c。 Expr[Seq[(String, Any)] ] =
seq.headOption match {
case Some(head) =>
c.universe.reify(
Seq((head.splice._1, head.splice._2))
seqToExprs(seq.tail).splice
)
case _ => c. Expr[Seq[(String, Any)](q "Seq.empty"/span>)
}
所以現在我決定回傳一個字串表示法(但是你可以按照你的意愿來操作它):
val elements = seqToExprs(accessorValues)
c.Expr[String](q"${elements}.mkString"/span>)
你可以把它當作:
import Macros._
class A(val a : Int)
class B(val b : Int) extends A(b)
class C(val c。Int) extends B(c)
//println(typeToString[List[Set[List[Double]]]]))
val c = new C(10)
println(accessors[C](c)) //列印(a, 10)(b, 10)(c, 10)
println(accessors[B](c)) //列印(a, 10)(b, 10)
println(accessors[A](c)) //列印(a, 10)。
而且,使用你的例子:
// Your example:
case class Person(name: String。
override val age: Int,
覆寫值地址。String, override val age: Int, override val address: String
) extends Details(age, address)
class Details(val age: Int, val address: String)。
val person = Person("Alex"/span>, 33, "Europe")
println(accessors[Details](person)) //列印(地址,歐洲)(年齡,33)。
println(accessors[Person](person)) //列印(address,Europe)(age,33)(name,Alex)
在這里有一個實作了宏的資源庫。
Scala 3.0引入了一個更安全、更簡潔的宏系統,如果你使用它,并且你想進一步了解,你可以閱讀這些文章:
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/309089.html
標籤:
