我试图用自定义属性来丰富一个类:
class MyClass {
def printNumber(n: Int) = {
println(n)
}
}
class MyClassWithName(myClass: MyClass, val name: String) {}
implicit def myClassWithName(myClass: MyClass, name: String) = new MyClassWithName(myClass, name)
然后我尝试像这样访问自定义属性name
...
val c = myClassWithName(new MyClass, "jonny")
c.printNumber(5)
...但它没有编译:
value printNumber is not a member of MyClassWithName.
我错过了什么吗? TX。
答案 0 :(得分:2)
你可能想要相反:
class Wrapper(original: OriginalClass) {
def printNumber(n: Int) = println(n)
def printName = println(original.name) // I added this method to justify wrapping of original
}
class OriginalClass(val name: String)
implicit def toWrapper(original: OriginalClass) = new Wrapper(original)
val x = new OriginalClass("johny")
// x: OriginalClass = OriginalClass@21788153
x.printName
// johny
x.printNumber(1)
// 1
请注意,较新版本的scala具有更简洁的implicit class
combination
答案 1 :(得分:2)
如果您只想添加name
属性而无需其他任何内容,您可以这样做:
object MyClassPlus {
private val map = scala.collection.mutable.Map.empty[MyClass,String]
}
implicit class MyClassPlus(val myClass: MyClass) extends AnyVal {
def name = MyClassPlus.map(myClass)
def name_= (value: String) {
MyClassPlus.map(myClass) = value
}
}
然后,您可以访问名称,就像它是MyClass
的成员一样:
scala> val c = new MyClass
c: MyClass = MyClass@78e312af
scala> c.name = "foo"
c.name: String = foo
scala> c.name
res4: String = foo
请注意,使用此方法时,equals
的{{1}}方法应测试引用相等性。否则,必须将MyClass
更改为使用引用相等。
如果您希望能够在运行时向对象添加许多属性,并且可以更改类的定义,则可以扩展Map
。
Dynamic
然后你可以添加和访问这样的属性:
import scala.language.dynamics
class MyClass extends Dynamic {
private val map = scala.collection.mutable.Map.empty[String,String]
// the type of value doesn't necessarily have to be String
def updateDynamic(name: String)(value: String) {
map(name) = value
}
def selectDynamic(name: String) = map(name)
}
如果无法更改类的定义,可以尝试进行某种类型的隐式转换:
scala> val c = new MyClass
c: MyClass = MyClass@50f85a5f
scala> c.name = "foo"
c.name: String = foo
scala> c.name
res6: String = foo
然后您可以添加和访问属性,但语法不太直观:
object MyClassPlus {
private val map = scala.collection.mutable.Map.empty[(MyClass,String),String]
}
implicit class MyClassPlus(val myClass: MyClass) extends AnyVal {
def update(name: String, value: String) {
MyClassPlus.map((myClass, name)) = value
}
def apply(name: String) = MyClassPlus.map((myClass, name))
}
答案 2 :(得分:1)
您的包装类MyClassWithName
包含myClass
和name
作为其成员。因此,要访问类printNumber
中的MyClass
函数,您需要先访问对象myClass
。
您可以编写一个getter方法,使用@BeanProperty
注释或者更好,使用案例类如下:
case class MyClassWithName(myClass: MyClass, val name: String)
val c = myClassWithName(new MyClass, "jonny")
c.myClass.printNumber(5)
那会编译。