scala:在特征中定义任何类型的变量

时间:2014-11-06 13:09:53

标签: scala types annotations traits

我有以下代码:

import scala.reflect.runtime.{universe => ru}

case class OutputAnnotation() extends scala.annotation.StaticAnnotation

trait SimpleTrait {

    var probe: Any 

    def outputs(): List[String] = {
        val ouputs: List[String] = Nil
        outputs
    }
}

class WorldProbe {
    @OutputAnnotation
    var population: Int = 0

    @OutputAnnotation
    var gdp: Float = 0

    var notIntersting: String = ""
}

class World extends SimpleTrait {
    var probe: Any = new WorldProbe
}

object Test {
    def main(args: Array[String]) {
        var w: World = new World
        var outp = w.outputs() 
    }
}

我的想法是让一些类都实现一些特性,SimpleTrait,它们应该要求它们定义一个Type ... hmm的变量探测器,这个类型不是真正的cleear,因为每个实现SimpleFeature的Class都会带有它自己的探针类型。因此,我可以在SimpleTrait中调用的唯一类型是Any。给定的代码编译,但执行会导致运行时出现堆栈溢出错误。 另外,我想从probe类中获取所有带有输出注释的变量。我怎么能这样做?

谢谢!

2 个答案:

答案 0 :(得分:3)

您可以使用类似这样的抽象类型

来执行此操作
trait Sim {
    type Probe
    var probe: Probe
}

class WorldProbe

class World extends Sim {
    type Probe = WorldProbe
    var probe: Probe = new WorldProbe
}

答案 1 :(得分:3)

您的堆栈溢出是因为您的outputs方法。由于某种原因,编译器没有抓取变量outputs,而是递归调用该方法。以下是具体修复:

def outputs(): List[String] = {
  Nil
}

在结构方面,我更希望看到SimpleTrait有一个通用参数,如下所示:

trait SimpleTrait[T] {
  var probe: T

  def outputs(): List[String] = Nil
}

class World extends SimpleTrait[WorldProbe] {
  var probe: WorldProbe = new WorldProbe
}

为了找到@OutputAnnotation的所有实例,有一些事情。 1)使用Java Annotations而不是Scala Annotations(每个人都这样做)。

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface OutputAnnotation {
}

然后2)使用Jackson的Annotation Introspector轻松找到并吐出数值。

object Test {
  def main(args: Array[String]): Unit = {
    import scala.collection.JavaConversions._
    import com.fasterxml.jackson.databind.introspect.{AnnotatedClass, JacksonAnnotationIntrospector}

    val x = new WorldProbe

    val introspector = new JacksonAnnotationIntrospector
    val ac = AnnotatedClass.construct(x.getClass, introspector, null)

    val outFields = ac.fields().filter(_.hasAnnotation(classOf[OutputAnnotation]))
    for (field <- outFields) {
      field.fixAccess()
      println(field.getName + " => " + field.getValue(x))
    }
  }
}

产生此输出:

population => 0
gdp => 0.0