2013-04-30 23 views
5

Ai đó có thể làm rõ lý do tại sao mã sau đây gây ra lỗi trùng khớp? MatchError có nghĩa là gì trong trường hợp này?Ghi đè giá trị đối tượng đồng hành và đối sánh Scala

class A { 
    def g = A.f 
} 

object A { 
    val f = "Object A" 
} 


class B extends A { 
    override val A.f = "Object B" 
} 

val b = new B 
b.g 

Vì điều này không có tác dụng, có cách nào để ghi đè lên đối tượng đồng hành val hoặc def tương tự như vậy không?

Trả lời

3

Trước tiên, tại sao bạn lại thấy một số MatchError. Một giá trị trên một đối tượng (A.f) được coi là một định danh ổn định (như tham chiếu Scala nói, "Thành viên ổn định là [...] thành viên được giới thiệu bởi các đối tượng hoặc định nghĩa giá trị của các loại không bay hơi").

Đây là những gì đầu ra typer trông giống như:

object A extends scala.AnyRef { 
    ... 
    private[this] val f: String = "Object A"; 
    <stable> <accessor> def f: String = A.this.f 
} 

Khi được sử dụng trong một bài tập, trình biên dịch "desugars" giao nhận dạng ổn định này (nó là ổn định là một điều kiện cần thiết) vào mô hình kết hợp:

<synthetic> private[this] val x$1: Unit = ("Object B": String("Object B") @unchecked) match { 
    case A.f =>() 
} 

Không thể đối sánh "Đối tượng B" với mẫu "Đối tượng A", vì vậy nó ném một số MatchError.

Để câu hỏi lớn hơn của bạn: bạn không thể/không nên ghi đè các giá trị và phương pháp trên đối tượng đồng hành. Tính đa hình áp dụng cho các lớp và các thể hiện của chúng, không áp dụng cho các phương thức hoặc giá trị tĩnh. Có lẽ một cách tốt hơn để suy nghĩ về chương trình của bạn mà không liên quan đến trọng số ghi đè/defs trên một đối tượng đồng hành.

+0

Cảm ơn bạn đã làm rõ! Tôi đồng ý với bạn về nhu cầu ghi đè đối tượng đồng hành nói chung, nhưng lý do tôi muốn làm ở đây là dành cho mục đích thử nghiệm, nơi tôi muốn thay thế một phương thức bên trong đối tượng đồng hành bằng một phương pháp khác. Ngoài ra, một số ngôn ngữ cho phép ghi đè các phương pháp tĩnh. – deepkimo

1

Điều này thật thú vị! Nếu bạn đặt các định nghĩa lớp thành một tập tin và biên dịch nó bằng cách sử scalac -print test.scala bạn sẽ thấy một cái gì đó như thế này,

[[syntax trees at end of     cleanup]] // scala 
package <empty> { 
    class A extends Object { 
    def g(): String = A.f(); 
    def <init>(): A = { 
     A.super.<init>(); 
    () 
    } 
    }; 
    object A extends Object { 
    private[this] val f: String = _; 
    <stable> <accessor> def f(): String = A.this.f; 
    def <init>(): A.type = { 
     A.super.<init>(); 
     A.this.f = "Object A"; 
    () 
    } 
    }; 
    class B extends A { 
    <synthetic> private[this] val x$1: runtime.BoxedUnit = _; 
    def <init>(): B = { 
     B.super.<init>(); 
     B.this.x$1 = { 
     case <synthetic> val x1: String = ("Object B": String("Object B")); 
     case5(){ 
      if (A.f().==(x1)) 
      { 
       val x2: String = x1; 
       matchEnd4(scala.runtime.BoxedUnit.UNIT) 
      } 
      else 
      case6() 
     }; 
     case6(){ 
      matchEnd4(throw new MatchError(x1)) 
     }; 
     matchEnd4(x: runtime.BoxedUnit){ 
      scala.runtime.BoxedUnit.UNIT 
     } 
     }; 
    () 
    } 
    } 
} 

Điều này cho thấy trình biên dịch tạo ra một lớp B với một khởi mà thực hiện một trận đấu kiểm tra để thấy rằng giá trị bạn đã sử dụng để ghi đè số val A.f bằng với giá trị ban đầu if (A.f().==(x1)). Dường như không hữu ích lắm phải không? Nếu chúng không bằng nhau, nó sẽ ném lỗi trận đấu bằng cách gọi case6(). Chúng tôi có thể xác nhận điều này bằng cách thay đổi định nghĩa của class B thành override val A.f = "Object A".

class B extends A { 
     override val A.f = "Object A" 
} 

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

Vậy làm thế nào để khắc phục? Bạn chỉ có thể làm được điều này,

class B extends A { 
     override def g = "Object B" 
} 
scala> val b = new B 
b: B = [email protected] 

scala> b.g 
res1: String = Object B 

hoặc

class B extends A { 
     val f = "Object B" 
} 
scala> val b = new B 
b: B = [email protected] 

scala> b.f 
res0: String = Object B 
+0

Bạn có thể xem xét sử dụng các đặc điểm: http://stackoverflow.com/a/7625150/1274818 – tysonjh

+0

Các bản sửa lỗi của bạn là một cách thông minh để tìm hiểu ví dụ mã đơn giản này, nhưng không phải là những gì tôi thực sự đang tìm kiếm, vì tôi muốn gọi phương pháp Af gốc. – deepkimo

+0

Có, các đặc điểm là một cách tốt để cấu trúc điều này, nhưng trong trường hợp của tôi, tôi muốn kiểm tra mã đã tồn tại mà không thay đổi mã chính. – deepkimo