2009-04-22 63 views
13

我希望能够使用this.type来定义一个方法来创建不可变案例类的新实例。事情是这样的:为什么不能将这个类型用于新实例

trait Expression 
{ 
    def left : Expression 
    def right : Expression 

    def new_with_changes(l : Expression, r : Expression) : this.type 
} 

case class Derived(left : Expression, right : Expression) 
{ 
    def new_with_changes(l : Expression, r : Expression) : this.type = 
    { 
    new Derived(left, right) 
    } 
} 

不幸的是,编译器会抱怨

test.scala:13: error: type mismatch; 
found : Derived 
required: Derived.this.type 
    new Derived(left, right) 
    ^
one error found 

怎么会在新的情况下,类不匹配this.type?

如果我将Base.new_with_changes中的this.type更改为Base,并且Derived.new_with_changes中的Derived.new_with_changes可以工作,但它似乎错过了this.type的好处。

编辑:问题的真正目的是为什么没有在Scala中有一个等价的方法来声明down的调用者执行downcast,与this.type所做的很相似,但是对于一般类型。我不认为这很容易,但它会很好。

回答

7

[注:我不建议你这么做。]有一个公平的你可以完成你想要的东西。对this.type的转换是谎言,但JVM不知道,并且不能抛出异常,因为单例类型是scala概念。

现在,如果你实际上在任何地方使用this.type的单例属性,这会让你匆匆忙忙。但是,如果你想要做的就是协变返回类型,而无需键入他们,所有的地方的巨大丑陋的演员唯一的小缺点的所有麻烦:

trait Expression 
{ 
    def left : Expression 
    def right : Expression 

    def new_with_changes(l : Expression, r : Expression) : this.type 
} 

case class Derived1(left : Expression, right : Expression) extends Expression { 
    def new_with_changes(l : Expression, r : Expression) = 
    Derived1(left, right).asInstanceOf[this.type] 

    def foo() = "Derived1" 
} 

case class Derived2(left : Expression, right : Expression) extends Expression { 
    def new_with_changes(l : Expression, r : Expression) = 
    Derived2(left, right).asInstanceOf[this.type] 

    def bar() = "Derived2" 
} 

而且在行动:

scala> Derived1(Derived1(null,null), null) 
res0: Derived1 = Derived1(Derived1(null,null),null) 

scala> res0.new_with_changes(res0, null).bar 
<console>:6: error: value bar is not a member of Derived1 
     res0.new_with_changes(res0, null).bar 
             ^

scala> res0.new_with_changes(res0, null).foo 
res2: java.lang.String = Derived1 

scala> Derived2(Derived2(null, null), null) 
res3: Derived2 = Derived2(Derived2(null,null),null) 

scala> res3.new_with_changes(null, res3).foo 
<console>:6: error: value foo is not a member of Derived2 
     res3.new_with_changes(null, res3).foo 
             ^

scala> res3.new_with_changes(null, res3).bar 
res6: java.lang.String = Derived2 
+0

哈克,但它的作品。如果我们能在语言中得到这样的东西,那很酷。 – 2009-04-27 06:34:15

8

this.type是此特定实例的唯一类型。它是一个单例类型 - 与同一类的任何其他实例不同的类型。这工作

class Foo { def f : this.type = this} 

但这并不不需要

class Foo { def f : this.type = new Foo} 

this.type经常,但它可以被用来表达无法表达,否则

一些制约因素例如,这里Inner类表示每个实例的外部方法将返回它所来自的特定Outer实例。

scala> class Outer{ class Inner { def outer : Outer.this.type = Outer.this}; def f(x : Inner) = println("ok")} 
defined class Outer 

scala> val o1 = new Outer 
o1: Outer = [email protected] 

scala> val o2 = new Outer 
o2: Outer = [email protected] 


scala> val in1 = new o1.Inner 
in1: o1.Inner = [email protected] 

scala> val in2 = new o2.Inner 
in2: o2.Inner = [email protected] 

scala> val o3 = in1.outer 
o3: o1.type = [email protected] 

scala> o1.f(new o3.Inner) 
ok 

scala> o1.f(new o2.Inner) 
<console>:8: error: type mismatch; 
found : o2.Inner 
required: o1.Inner 
     o1.f(new o2.Inner) 

这篇文章有使用this.type使跨方法边界子链接的另一个很好的例子:http://scalada.blogspot.com/2008/02/thistype-for-chaining-method-calls.html

scala> class A { def method1: this.type = this } 
defined class A 

scala> class B extends A { def method2: this.type = this } 
defined class B 

scala> val b = new B 
b: B = [email protected] 

scala> b.method1.method2 
res3: b.type = [email protected] 
+2

除了this.type之外,有一种方法可以做我想做的事情,其中​​基类方法可以声明为返回调用方将会下调的子类型实例,方式与与this.type调用者代码确实。 – 2009-04-22 19:19:18