反射を使用してScalaで適切なtoString()メソッドを作成する方法は?
-
19-09-2019 - |
質問
クラスへのデバッグタイムの内省を簡単にするために、問題のオブジェクトのベースクラスで一般的なトストリング方法を作成したいと思います。パフォーマンスクリティカルコードではないため、リフレクションを使用してフィールド名/値ペアを印刷したいと思います( "x = 1、y = 2"など)。
これを行う簡単な方法はありますか?私はいくつかの潜在的なソリューションを試してみましたが、セキュリティアクセスの問題などに対抗しました。
明確にするために、基本クラスのtoString()メソッドは、それから継承するクラスの公共ヴァルを反射的に反復的に反復する必要があります。
解決
import util._ // For Scala 2.8.x NameTransformer
import scala.tools.nsc.util._ // For Scala 2.7.x NameTransformer
/**
* Repeatedly run `f` until it returns None, and assemble results in a Stream.
*/
def unfold[A](a: A, f: A => Option[A]): Stream[A] = {
Stream.cons(a, f(a).map(unfold(_, f)).getOrElse(Stream.empty))
}
def get[T](f: java.lang.reflect.Field, a: AnyRef): T = {
f.setAccessible(true)
f.get(a).asInstanceOf[T]
}
/**
* @return None if t is null, Some(t) otherwise.
*/
def optNull[T <: AnyRef](t: T): Option[T] = if (t eq null) None else Some(t)
/**
* @return a Stream starting with the class c and continuing with its superclasses.
*/
def classAndSuperClasses(c: Class[_]): Stream[Class[_]] = unfold[Class[_]](c, (c) => optNull(c.getSuperclass))
def showReflect(a: AnyRef): String = {
val fields = classAndSuperClasses(a.getClass).flatMap(_.getDeclaredFields).filter(!_.isSynthetic)
fields.map((f) => NameTransformer.decode(f.getName) + "=" + get(f, a)).mkString(",")
}
// TEST
trait T {
val t1 = "t1"
}
class Base(val foo: String, val ?? : Int) {
}
class Derived(val d: Int) extends Base("foo", 1) with T
assert(showReflect(new Derived(1)) == "t1=t1,d=1,??=1,foo=foo")
他のヒント
例:
override def toString() = {
getClass().getDeclaredFields().map { field:Field =>
field.setAccessible(true)
field.getName() + ": " + field.getType() + " = " + field.get(this).toString()
}.deepMkString("\n")
}
Java Reflection APIを使用するので、忘れないでください Java.lang.Reflect._インポート
また、キャッチする必要があるかもしれません Illegalaccessexception field.get(this)はいくつかのシナリオで呼び出しますが、これは出発点としてのみ意味します。
SCALAケースクラスがこれらのコンパイラで生成された方法を取得することを知っていますか?
- toString():文字列
- Equals(その他:ANY):Boolean
- ハッシュコード:int
また、「新しい」コンストラクターとパターンマッチングのコンパニオンオブジェクトを取得します。
生成された toString()
あなたが説明するものによく似ています。
Scalaはパブリックフィールドを生成しません。彼らはすべてプライベートになるでしょう。アクセサーの方法は公開されるものです、それらを振り返ります。次のようなクラスが与えられます:
class A {
var x = 5
}
生成されたbytecodeは次のように見えます。
private int x;
public void x_$eq(int);
public int x();
所属していません StackOverflow