2011-02-01 61 views
6

Giả sử tôi có một lớp cơ sởđặc điểm và các loại trừu tượng

abstract class Base { 

    type B<: Base 

    def rep:String 

    def copy:B 
} 

class MyBase(override val rep:String) extends Base { 
    type B = MyBase 

override def copy = new MyBase(rep) 
} 

sau đó tôi cố gắng thêm đặc điểm khác như một mixin, mà tôi muốn các kiểu trả về cho bản sao là loại thích hợp (nghĩa là gọi sao chép trên mixin trả về một loại mixin, bằng cách đặt B cho loại thích hợp). Tôi đã không thể có được điều này để biên dịch, hoặc thậm chí để hiểu nơi mà các từ khóa ghi đè nên đi.

được sửa đổi: Tôi đã tinh chế ví dụ

abstract class Base { 


    type B <: Base 

    def rep:String 

    def copy:B 

} 

class MyBase(val rep:String) extends Base { 

    type B = MyBase 

    def copy = new MyBase(rep) 
} 


trait DecBase extends Base { 

    abstract override def rep = "Rep: "+super.rep 
} 

Câu hỏi của tôi là, làm thế nào để khai báo một loại B thích hợp và sao chép phương pháp DecBase, do đó các bản sao trả về một DecBase, và cũng có thể, tại sao thắng' t biên dịch này?

println(((new MyBase("ofer") with DecBase)).rep) 

Đây là điều tôi đã đạt được trong Java (với một số sự khó chịu, sử dụng các loại chung đệ quy). Tôi chắc chắn rằng nó có thể làm điều gì đó đẹp hơn ở Scala.

Sửa

Sử dụng

trait DecBase extends Base { 

    override type B = DecBase 
    abstract override val rep= "Dec:"+super.rep 
    abstract override def copy = new MyBase(rep) with DecBase 
} 

tôi nhận được các lỗi biên dịch sau

error: overriding type B in class MyBase, which equals com.amadesa.scripts.MyBase; 
type B in trait DecBase, which equals com.amadesa.scripts.DecBase has incompatible type 
println(((new MyBase("ofer") with DecBase)).rep) 

error: overriding type B in class MyBase, which equals com.amadesa.scripts.MyBase; 
type B in trait DecBase, which equals com.amadesa.scripts.DecBase has incompatible type 
abstract override def copy = new MyBase(rep) with DecBase 

Trả lời

2

tôi giả sử sự pha trộn của bạn trong trông giống như sau

trait MixIn extends Base { 
    override B = MixinBase 
    override def copy = new MixinBase(rep) 
} 

Tôi nghĩ rằng override trên MyBase là một phần của sự cố. Nó không cần thiết và gây nhầm lẫn cho trình biên dịch.

Nếu số copy trên Base trên thực tế có thực hiện, hãy thực hiện override cần thiết, bạn cần phải thông báo cho trình biên dịch biết sử dụng phương pháp nào. Nếu nó không rõ ràng với nó, nó ném lên bàn tay của nó và đưa ra một lỗi. Thử cái này.

val b = new MyBase(rep) with MixIn { 
    override def copy = MixIn.super.copy 
} 

MixIn.super.copy là cuộc gọi đến số bạn muốn.

Bạn có thể muốn xem lại trang này trên Scala Class Linearization để hiểu điều gì sẽ xảy ra khi bạn có triển khai cạnh tranh về phương pháp trong một loại.

Chỉnh sửa: oh đây là vấn đề hoàn toàn khác. Đó là val trong case MyBase(val rep:String). Bạn không thể ghi đè lên một val với một def bởi vì một val được giả định là không thay đổi. Bạn có thể ghi đè lên một def hoặc var với một val, nhưng không phải là cách khác xung quanh. Làm cho nó:

trait DecBase extends Base { 
    abstract override val rep = "Rep: "+super.rep 
} 

Vui lòng bao gồm lỗi trình biên dịch vào lần sau. Nó làm cho nó dễ dàng hơn nhiều để xem vấn đề là gì.

+0

Tôi đã tinh chỉnh câu hỏi. – user44242

+0

Đã chỉnh sửa lại, thêm lỗi trình biên dịch lần này. Điều quan trọng đối với tôi là kiểu trả về đúng cho phương thức sao chép. – user44242

+0

Hiện tại tôi đang gặp sự cố khi hoạt động. Để bắt đầu, bạn không thể ghi đè B thành DecBase vì DecBase không phải là kiểu con của MyBase. Nhưng sau khi sửa xong, tôi vẫn gặp lỗi. Trình biên dịch dường như không thích loại B = MyBase, nhưng nó có thể khác. – sblundy

0

Tôi nghĩ rằng nó được kết nối bằng cách nào đó với số val rep trong lớp MyBase. Bạn nên xác định MyBase tóm tắt, nếu bạn không triển khai def rep.

abstract class Base { 
    type B <: Base 
    def rep:String 
    def copy: B 
} 

class MyBase(val repVal: String) extends Base { 
    type B = MyBase 
    def rep = repVal 
    def copy = new MyBase(repVal) 
} 


trait DecBase extends Base { 
    abstract override def rep = "Rep: " + super.rep 
} 

println(((new MyBase("ofer"))).rep) // prints: ofer 
println(((new MyBase("ofer") with DecBase)).rep) // prints: Rep: ofer 

Hope this helps:

Dưới đây là ví dụ làm việc.

+0

Không. Ở Scala, có một def hoặc val là hoán đổi cho nhau. điều val đại diện là việc thực hiện đại diện. – user44242

+0

Xin lỗi, có vẻ như tôi đã quên điều gì đó cơ bản :) Cảm ơn bạn đã chỉ ra! – tenshi

0

Vì vậy, như tôi hiểu nó, mục đích là để có thể làm:

val myBase: MyBase = new MyBase("alone") 
val myBaseCopy: MyBase = myBase.copy 

val decBase: DecBase = new MyBase("mixed") with DecBase 
val decBaseCopy: DecBase = decBase.copy 

Hãy viết lại mã của bạn để sử dụng giới hạn loại thay vì bình đẳng trong type tờ khai của bạn (và cũng để sửa chữa không phù hợp giữa val repdef rep được cất giấu một số lỗi biên dịch khác):

abstract class Base { 
    type B <: Base 
    def rep: String 
    def copy: B 
} 

class MyBase(_rep: String) extends Base { 
    type B <: MyBase 
    def rep = _rep 
    def copy = new MyBase(rep) 
} 

trait DecBase extends Base { 
    override type B <: DecBase 
    override abstract def rep = "Rep: " + super.rep 
} 

này bây giờ nói rằng MyBase.copy phải trả lại một MyBase hoặc một lớp con, và DecBase.copy sh ould trả về một số DecBase hoặc một lớp con. Tôi tin rằng đó là những gì bạn muốn, phải không? Bây giờ lỗi trình biên dịch kết quả là rõ ràng:

temp.scala:10: error: type mismatch; 
found : this.MyBase 
required: MyBase.this.B 
    def copy = new MyBase(rep) 
      ^
one error found 

Vì vậy, bạn đang quay trở lại MyBase nhưng bạn thực sự cần phải trả lại lớp con, ví dụ: bạn muốn trả lại new MyBase(rep) with DecBase thay vì new MyBase(rep), nhưng chỉ khi đối tượng của bạn được khai báo là new MyBase(...) with DecBase. Tôi không biết cách nào để làm điều đó, mặc dù có lẽ bạn có thể xem adding a trait after an object has been constructed.

+0

Không biên dịch, ngay cả khi tôi hạn chế Base và MyBase, và quên DecBase. Trình biên dịch than phiền: lỗi: loại không phù hợp; Đã tìm thấy : com.amadesa.scripts.MyBase bắt buộc: MyBase.this.B def copy = new MyBase (rep) – user44242

+1

Chính xác. Bạn muốn 'DecBase.copy' của bạn trả về một' DecBase' nhưng điều đó là không thể bởi vì 'MyBase' thực sự đang tạo đối tượng và' MyBase' không biết gì về 'DecBase'. Bạn đang mong đợi 'DecBase' bằng cách nào đó thay đổi dòng' new MyBase (rep) 'thành' new MyBase (rep) với DecBase'. – Steve

Các vấn đề liên quan