Scala - 从外部向类添加成员变量

时间:2015-07-07 15:12:57

标签: scala

是否可以从类外部向类中添加成员变量? (或者模仿这种行为?)

以下是我尝试做的一个例子。我已经使用隐式转换向final int top = 50; final Duration windowSize = standardMinutes(60); final Duration windowPeriod = standardMinutes(10); final SlidingWindows window = SlidingWindows.of(windowSize).every(windowPeriod); options.setWorkerMachineType("n1-standard-16"); options.setWorkerDiskType("compute.googleapis.com/projects//zones//diskTypes/pd-ssd"); options.setJobName(applicationName); options.setStreaming(true); options.setRunner(DataflowPipelineRunner.class); final Pipeline pipeline = Pipeline.create(options); // Get events final String eventTopic = "projects/" + options.getProject() + "/topics/eventLog"; final PCollection<String> events = pipeline .apply(PubsubIO.Read.topic(eventTopic)); // Create toplist final PCollection<List<KV<String, Long>>> topList = events .apply(Window.into(window)) .apply(Count.perElement()) //as eventIds are repeated // get top n to get top events .apply(Top.of(top, orderByValue()).withoutDefaults()); 添加了其他函数,因此我向RDD添加了一个变量。我猜这不起作用,因为变量在ExtendedRDDFunctions调用转换后丢失了。

有没有办法获得这种功能?这是错误的做法吗?

rdd.setMember(string)

编辑: 我使用以下函数:首先调用implicit def toExtendedRDDFunctions(rdd: RDD[Map[String, String]]): ExtendedRDDFunctions = { new ExtendedRDDFunctions(rdd) } class ExtendedRDDFunctions(rdd: RDD[Map[String, String]]) extends Logging with Serializable { var member: Option[String] = None def getMember(): String = { if (member.isDefined) { return member.get } else { return "" } } def setMember(field: String): Unit = { member = Some(field) } def queryForResult(query: String): String = { // Uses member here } } ,然后调用rdd.setMember("state")

2 个答案:

答案 0 :(得分:3)

由于每次调用ExtendedRDDFunctions中定义的方法时都会应用隐式转换,因此每次调用ExtendedRDDFunctionssetMember都会创建一个新的queryForResult实例。这些实例不共享任何成员变量。

您基本上有两种选择:

  1. Map[RDD, String]的伴随对象中维护ExtendedRDDFunctions,用于将member值分配给setMember中的RDD。当你为一系列错误引入全球状态和公开陷阱时,这是一个邪恶的选择。
  2. 创建一个包含member值的包装类,并由setMember方法返回:

    case class RDDWithMember(rdd: RDD[Map[String, String]], member: String) extends RDD[Map[String, String]] {
      def queryForResult(query: String): String = {
        // Uses member here
      }
    
      // methods of the RDD interface, just delegate to rdd
    }
    
    implicit class ExtendedRDDFunctions(rdd: RDD[Map[String, String]]) {
      def setMember(field: String): RDDWithMember = {
        RDDWithMember(rdd, field)
      }
    }
    

    除了省略的全局状态,此方法也更安全,因为您无法在没有queryForResult的实例上调用member。唯一的缺点是您必须委派RDD的所有成员,并且queryForResult本身未定义RDD。 第一个问题可能可以通过一些宏魔术来解决(搜索“委托”或“代理”和“宏”)。 可以通过在ExtendedRDDFunctions中定义额外的扩展方法来解决后一个问题,该方法会检查RDD是否为RDDWithMember

    implicit class ExtendedRDDFunctions(rdd: RDD[Map[String, String]]) {
      def setMember(field: String): RDDWithMember = // ...
    
      def queryForResult(query: String): Option[String] = rdd match {
        case wm: RDDWithMember => Some(wm.queryForResult(query))
        case _ => None
      }
    }
    

答案 1 :(得分:0)

import ExtendedRDDFunctions._

将导入Companion对象中的所有属性和函数,以便在类的主体中使用。

根据您的用法寻找delagate模式。