[英]Scala: How to enrich a class with a property
I'm trying to enrich a class with a custom property: 我正在尝试通过自定义属性丰富类:
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)
Then I try to access custom property name
like this... 然后,我尝试像这样访问自定义属性
name
...
val c = myClassWithName(new MyClass, "jonny")
c.printNumber(5)
... but it does not compile: ...但是它不能编译:
value printNumber is not a member of MyClassWithName.
Am I missing something? 我想念什么吗? Tx.
Tx。
You probably wanted the opposite: 您可能想要相反的情况:
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
Note, that newer versions of scala has more concise syntax with implicit class
combination 注意,新版本的scala具有
implicit class
组合的更简洁的语法
If you only want to add a name
property and nothing else you could do it like this: 如果您只想添加
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
}
}
You can then access name as if it's a member of MyClass
: 然后,您可以像访问
MyClass
一样访问name:
scala> val c = new MyClass
c: MyClass = MyClass@78e312af
scala> c.name = "foo"
c.name: String = foo
scala> c.name
res4: String = foo
Note that with this approach the equals
method of MyClass
should test for reference equality. 请注意,使用这种方法,
MyClass
的equals
方法应该测试引用是否相等。 Otherwise the Map
has to be changed to use reference equality instead. 否则,必须将
Map
更改为使用引用相等。
If you want to be able to add many properties to an object at runtime and you can change the definition of the class you can extend Dynamic
. 如果您希望能够在运行时向对象添加许多属性,并且可以更改类的定义,则可以扩展
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)
}
Then you can add and access properties like this: 然后,您可以添加和访问如下属性:
scala> val c = new MyClass
c: MyClass = MyClass@50f85a5f
scala> c.name = "foo"
c.name: String = foo
scala> c.name
res6: String = foo
If you can't change the definition of the class, you could try to do some sort of implicit conversion like this: 如果您不能更改类的定义,则可以尝试执行某种隐式转换,如下所示:
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))
}
Then you can add and access properties, but with a less intuitive syntax: 然后,您可以添加和访问属性,但语法不太直观:
scala> val c1 = new MyClass
c1: MyClass = MyClass@635b4736
scala> val c2 = new MyClass
c2: MyClass = MyClass@1be2e9e5
scala> c1("name") = "foo"
scala> c2("name") = "bar"
scala> c1("name")
res2: String = foo
scala> c2("name")
res3: String = bar
Your wrapper class MyClassWithName
contains myClass
and name
as its members. 包装器类
MyClassWithName
包含myClass
和其成员name
。 So, in order to access the printNumber
function in the class MyClass
, you need to access the object myClass
first. 因此,为了访问
MyClass
类中的printNumber
函数,您需要首先访问对象myClass
。
You can write a getter method, use @BeanProperty
annotation or better yet, use a case class as follows: 您可以编写一个getter方法,使用
@BeanProperty
注解或更好的方法,使用一个case类,如下所示:
case class MyClassWithName(myClass: MyClass, val name: String)
val c = myClassWithName(new MyClass, "jonny")
c.myClass.printNumber(5)
That would compile. 那会编译。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.