鉴于一个特点MyTrait
:
trait MyTrait {
def doSomething = println("boo")
}
Run Code Online (Sandbox Code Playgroud)
它可以与extends
or 混合成一个类with
:
class MyClass extends MyTrait
Run Code Online (Sandbox Code Playgroud)
它也可以在实例化一个新实例时混合:
var o = new MyOtherClass with MyTrait
o.doSomething
Run Code Online (Sandbox Code Playgroud)
但是......可以将特征(或任何其他如果产生影响的特征)添加到现有实例中吗?
我在Java中使用JPA加载对象,我想使用traits为它们添加一些功能.有可能吗?
我希望能够按如下方式混合特征:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
o = o with MyTrait //adding trait here, rather than during construction
o.doSomething
Run Code Online (Sandbox Code Playgroud)
Goo*_*han 26
我有这个用法的想法:
//if I had a class like this
final class Test {
def f = println("foo")
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](val obj:Test) extends MyTrait
}
Run Code Online (Sandbox Code Playgroud)
你可以使用这个特性如下:
import MyTrait._
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
Run Code Online (Sandbox Code Playgroud)
为您的示例代码:
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
Run Code Online (Sandbox Code Playgroud)
我希望这可以帮到你.
更新
object AnyTrait {
implicit def innerObj[T](o: MixTest[T]):T = o.obj
def ::[T](o: T) = new MixTest(o)
final class MixTest[T] private[AnyTrait](val obj: T) extends MyTrait
}
Run Code Online (Sandbox Code Playgroud)
但是这种模式有一些限制,你不能使用已经定义的一些隐式辅助方法.
val a = new Test
a.f
val b = a :: AnyTrait
b.f1
b.f
val c = "say hello to %s" :: AnyTrait
println(c.intern) // you can invoke String's method
println(c.format("MyTrait")) //WRONG. you can't invoke StringLike's method, though there defined a implicit method in Predef can transform String to StringLike, but implicit restrict one level transform, you can't transform MixTest to String then to StringLike.
c.f1
val d = 1 :: AnyTrait
println(d.toLong)
d.toHexString // WRONG, the same as above
d.f1
Run Code Online (Sandbox Code Playgroud)
axe*_*l22 22
JVM中的现有运行时对象在堆上具有特定大小.添加特征将意味着改变其在堆上的大小,并改变其签名.
因此,唯一的方法是在编译时进行某种转换.
Scala中的Mixin组合发生在编译时.编译器可能做的是在现有对象A周围创建一个包装器B,其类型相同,只是将所有调用转发到现有对象A,然后将特征T混合到B.但是,这并没有实现.如果可能的话,这是值得怀疑的,因为对象A可能是最终类的一个实例,它不能被扩展.
总之,mixin组合在现有对象实例上是不可能的.
更新:
与Googol Shan提出的智能解决方案相关,并将其推广到任何特性,这是我所得到的.我们的想法是在特征中提取常见的mixin功能DynamicMixinCompanion
.然后,客户端应该DynamicMixinCompanion
为他想要具有动态mixin功能的每个特征创建一个扩展的伴随对象.此伴随对象需要定义创建的匿名特征对象(::
).
trait DynamicMixinCompanion[TT] {
implicit def baseObject[OT](o: Mixin[OT]): OT = o.obj
def ::[OT](o: OT): Mixin[OT] with TT
class Mixin[OT] protected[DynamicMixinCompanion](val obj: OT)
}
trait OtherTrait {
def traitOperation = println("any trait")
}
object OtherTrait extends DynamicMixinCompanion[OtherTrait] {
def ::[T](o: T) = new Mixin(o) with OtherTrait
}
object Main {
def main(args: Array[String]) {
val a = "some string"
val m = a :: OtherTrait
m.traitOperation
println(m.length)
}
}
Run Code Online (Sandbox Code Playgroud)
我通常使用a implicit
将新方法混合到现有对象中.
如果我有以下代码,请参阅:
final class Test {
def f = "Just a Test"
...some other method
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object HelperObject {
implicit def innerObj(o:MixTest) = o.obj
def mixWith(o:Test) = new MixTest(o)
final class MixTest private[HelperObject](obj:Test) extends MyTrait
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用MyTrait
已经存在的对象Test的方法.
val a = new Test
import HelperObject._
val b = HelperObject.mixWith(a)
println(b.f)
b.doSomething
Run Code Online (Sandbox Code Playgroud)
在您的示例中,您可以像这样使用:
import HelperObject._
val o = mixWith(DBHelper.loadMyEntityFromDB(primaryKey));
o.doSomething
Run Code Online (Sandbox Code Playgroud)
我正在考虑一个完美的语法来定义这个HelperObject:
trait MyTrait {
..some method
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](obj:Test) extends MyTrait
}
//then you can use it
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
// for your example
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
22748 次 |
最近记录: |