为什么我不能将字段添加到scala隐式类?

时间:2014-10-25 08:43:24

标签: scala

为什么你不能在隐式类中添加字段?

例如,下面的代码不存储originalName字段

object Implicit1 {

  implicit class AI1(c: Class[_]) {
    private var originalName = ""

    def setOriginalName(str: String) = originalName = str

    def getOriginalName=originalName
  }
}

3 个答案:

答案 0 :(得分:6)

隐式类是一个可以作为类的包装器隐式调用的类(在本例中是Class的实例)。它绝对可以有var;从这个意义上说,你的代码工作正常。

问题是你无法获得AI1的实例。所以你创建它,加载var,然后扔掉它。它不是原始c: Class[_]实例的一部分;这里没有猴子修补。它只会让您输入(new AI1(c)).whicheverMethodYouPutOnAI1

如果你确实有办法获得AI1,那么当你写完它时,你将无法再次获得cAI1不是Class[_]的代理,只是拥有它的实例。现在你的getter和setter不会在暴露var时添加任何东西。所以你可能意味着类似

implicit class AI1(val underlying: Class[_]) {
  var originalName = ""
  def hasName = this
}

现在你可以做像

这样的事情
val named = "fish".getClass.hasName
named.originalName = "salmon"
println(s"${named.originalName} ${named.underlying}")

答案 1 :(得分:1)

正如Rex Kerr所提到的,每次需要时都会创建隐式类。因此,每次都会获得隐式类的新实例,存储在字段中的值已丢失。

scala> val clz = "str".getClass
clz: Class[_ <: String] = class java.lang.String

scala> val impA: AT1 = clz
impA: Imp.AT1 = Imp$AT1@2d96543c

scala> val impB: AT1 = clz
impB: Imp.AT1 = Imp$AT1@7a560583

scala> impA == impB
res2: Boolean = false

这是一种解决方法:

scala> :paste
// Entering paste mode (ctrl-D to finish)

object Imp {
   object AT1 {
     val clzBuffer = collection.mutable.Buffer[Class[_]]()
     val strBuffer = collection.mutable.Buffer[String]()
     def setName(clz: Class[_], name: String): Unit = {
       val ind = clzBuffer indexWhere (_ eq clz)
       if(ind == -1) {
         clzBuffer += clz
         strBuffer += name
       }
       else {
         strBuffer(ind) = name
       }
     }
     def getName(clz: Class[_]): String = {
       val ind = clzBuffer indexWhere (_ eq clz)
       if(ind == -1) "" else strBuffer(ind)
     }
   }

   implicit class AT1(c: Class[_]) {
     def originalName: String = AT1.getName(c)
     def originalName_=(name: String) = AT1.setName(c, name)
   }
} 

// Exiting paste mode, now interpreting.

defined object Imp

scala> import Imp._
import Imp._

scala> val clz = "str".getClass
clz: Class[_ <: String] = class java.lang.String

scala> clz.originalName
res0: String = ""

scala> clz.originalName = "IamHere"
clz.originalName: String = IamHere

scala> clz.originalName
res1: String = IamHere

答案 2 :(得分:0)

概括和抽象一点我使用以下方法:

implicit class class_extension(val class_to_extend: class_to_extend) {
   import class_extension._
   private val fields = class_extension_fields_map.getOrElseUpdate(class_to_extend, class_extension_fields(default_value_1, default_value_2))

   def a = fields.a
   def a_=(value: Int) = fields.a = value
   def b = fields.b
   def b_=(value: Int) = fields.b = value
}
object class_extension {
   private case class class_extension_fields(var a: Int, var b: Boolean)
   private val class_extension_fields_map = new HashMap[class_to_extend, class_extension_fields]
}

这基本上允许在某个上下文中“扩展”类,例如将字段添加到图的 - 所有 - 节点以应用某种算法。