Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reflection 如何使用反射在scala中创建一个像样的toString()方法?_Reflection_Scala_Tostring - Fatal编程技术网

Reflection 如何使用反射在scala中创建一个像样的toString()方法?

Reflection 如何使用反射在scala中创建一个像样的toString()方法?,reflection,scala,tostring,Reflection,Scala,Tostring,为了简化类的调试时内省,我想在基类中为相关对象创建一个通用的toString方法。由于它不是性能关键的代码,我想使用反射来打印字段名/值对(“x=1,y=2”等) 有没有一个简单的方法可以做到这一点?我尝试了几种可能的解决方案,遇到了安全访问问题等 为了清楚起见,基类中的toString()方法应该反射地迭代继承自它的任何类中的公共VAL,以及混合在其中的任何特征。示例: override def toString() = { getClass().getDeclaredFields().m

为了简化类的调试时内省,我想在基类中为相关对象创建一个通用的toString方法。由于它不是性能关键的代码,我想使用反射来打印字段名/值对(“x=1,y=2”等)

有没有一个简单的方法可以做到这一点?我尝试了几种可能的解决方案,遇到了安全访问问题等

为了清楚起见,基类中的toString()方法应该反射地迭代继承自它的任何类中的公共VAL,以及混合在其中的任何特征。

示例:

override def toString() = {
  getClass().getDeclaredFields().map { field:Field => 
    field.setAccessible(true)
    field.getName() + ": " + field.getType() + " = " + field.get(this).toString()
  }.deepMkString("\n")
}
使用Java反射API,所以不要忘记导入Java.lang.reflect.\uz


此外,您可能需要在字段上捕获IllegalAccessException。在某些情况下,get(this)调用,但这只是一个起点。

Scala不会生成任何公共字段。他们都是私人的。访问器方法是公开的,反映在这些方法上。给定一个类,如:

class A {
  var x = 5
}
生成的字节码如下所示:

private int x;
public void x_$eq(int);
public int x();
用于Scala 2.8.x NameTransformer的导入工具 为scala 2.7.x NameTransformer导入scala.tools.nsc.util.\u// /** *反复运行'f',直到它返回None,然后将结果汇编成一个流。 */ def展开[A](A:A,f:A=>选项[A]):流[A]={ Stream.cons(a,f(a).map(展开(u,f)).getOrElse(Stream.empty)) } def get[T](f:java.lang.reflect.Field,a:AnyRef):T={ f、 setAccessible(true) f、 得到(a).a代替[T] } /** *@如果t为null,则返回None,否则返回部分(t)。 */ def optNull[T optNull(c.getSuperclass)) def showReflect(a:AnyRef):字符串={ val fields=classAndSuperClasses(a.getClass).flatMap(u.getDeclaredFields).filter(!u.isSynthetic) fields.map((f)=>NameTransformer.decode(f.getName)+“=”+get(f,a)).mkString(“,”) } //试验 性状T{ val t1=“t1” } 类基(val foo:String,val???:Int){ } 派生类(val d:Int)用T扩展基(“foo”,1) 断言(showReflect(新派生的(1))=“t1=t1,d=1,?=1,foo=foo”)
您是否知道Scala case类会获得以下编译器生成的方法:

  • toString():字符串
  • 等于(其他:任意):布尔值
  • hashCode:Int
它们还为“newless”构造函数和模式匹配获得伴生对象


生成的
toString()
与您描述的非常相似。

这不应该是特征吗?
trait-toString[a]
?这可能是最干净的方法,我还没有想到它会如何影响我的对象继承权。我有一些属性访问问题,目前无法解释。这里的答案,特别是使用Apache ReflectionStringBuilder,不是一个坏主意:我已经使用了类似的方法,但我获得了很多访问权限我对此感到困惑,因为如果我有这样的代码:class Foo{val bar=3},那么如果我从另一个类调用Foo.getDeclaredField(“bar”),结果字段对象将具有修饰符“public”。我一直在使用java.lang.reflect.Modifier来解码修饰符字段,但它不起作用。这是在2.7.7中,所以我不确定它在这方面是否与2.8有所不同。我发现
val obj=field.get(This);val str=obj.asInstanceOf[String]
不起作用。奇怪的是,对于那些使用Scala 2.10的人来说,只要用mkstring替换deepMkString就行了。我相信很久以前我就知道这一点。谢谢!是的,case类很神奇。不幸的是,出于各种原因,我没有在这里使用它们。不过,我确实使用了您在其他地方列出的所有功能。我确信我的toString特性可以做到未来的le case类。另外,昨晚在IRC上很高兴见到你,小世界。我应该提到,我现在坚持使用2.7.7。我不确定你在代码中使用的一些新的2.8结构,结果出现了空指针异常。不过,这看起来是一种相当干净的方法,所以答案就在你身上!
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")