2010-01-02 42 views
33

Ví dụ sau đây là từ sách 'Lập trình trong Scala'. Cho một lớp 'Rational' và định nghĩa phương pháp sau đây:Scala: phương thức toán tử quá tải

def add(that: Rational): Rational = 
    new Rational(
     this.numer * that.denom + that.numer * this.denom, 
     this.denom * that.denom 
    ) 

tôi thành công có thể quá tải phương thức add với một phiên bản tiện lợi mà có một đối Int, và tận dụng định nghĩa trên:

def add(that: Int): Rational = 
    add(new Rational(that, 1)) 

Không có vấn đề gì cho đến nay.

Bây giờ, nếu tôi thay đổi tên phương pháp để một tên phong cách điều hành:

def +(that: Rational): Rational = 
    new Rational(
     this.numer * that.denom + that.numer * this.denom, 
     this.denom * that.denom 
    ) 

Và tình trạng quá tải như vậy:

def +(that: Int): Rational = 
    +(new Rational(that, 1)) 

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

(fragment of Rational.scala):19: error: value unary_+ is not a member of this.Rational 
+(new Rational(that, 1)) 
^ 

Tại sao trình biên dịch tìm kiếm một phiên bản đơn nhất của phương thức +?

Trả lời

50

Trong Scala, bất kỳ cấu trúc của các loại +x, -x, ~x!x được chuyển thành một phương pháp gọi x.unary_+, vv Đây là một phần để cho phép cú pháp Java giống như của việc có !b như sự phủ định của boolean b, hoặc -x làm phủ định số x.

Do đó, đoạn mã +(new Rational(that, 1)) được dịch sang (new Rational(that,1)).unary_+ và vì Rational không có phương pháp này, bạn sẽ gặp phải lỗi biên dịch. Bạn sẽ nhận được lỗi này chỉ khi chức năng của bạn được gọi là +, -, ~ hoặc ! vì đây là những ký tự duy nhất mà Scala cho phép là toán tử đơn nhất. Ví dụ: nếu bạn gọi hàm @+, thì mã sẽ biên dịch tốt.

Mặc dù, tôi sẽ đề nghị bằng văn bản cho add chức năng ghi đè như:

def +(that: Int): Rational = 
    this + (new Rational(that, 1)) 

code này cho thấy mục đích của chức năng của bạn tốt hơn - bạn thêm mới Rational xây dựng từ một số nguyên như một tử số và mẫu số 1 như đến this. Cách viết này được dịch sang this.+(new Rational(that, 1)), đó là những gì bạn muốn - gọi hàm + trên this.

Lưu ý rằng bạn có thể sử dụng ký hiệu infix tuy nhiên chức năng này được gọi. Ví dụ, nếu bạn thay đổi tên trở lại add, bạn vẫn có thể tiếp tục định nghĩa như sau:

def add(that: Int): Rational = 
    this add (new Rational(that, 1)) 
3

Bạn chưa quy định các nhà điều hành + nhị phân, bạn đã chỉ định các nhà điều hành + unary.

Vì vậy, thay vì:

def +(that: Int): Rational = 
    +(new Rational(that, 1)) 

Bạn cần phải viết này:

def +(that: Int): Rational = 
    this +(new Rational(that, 1)) 
5

Nếu bạn gọi + với rõ ràng this, cần làm việc

def +(that: Int): Rational = this.+(new Rational(that, 1)) 

Scala cho phép xác định toán tử đơn nhất có thể được sử dụng trong ký hiệu toán tử tiền tố. Ví dụ, bạn có thể sử dụng + như một nhà điều hành tiền tố để đạt được cùng:

def unary_+: Rational = this.+(new Rational(that, 1)) 
val a = new Rational(3,2) 
val b = +a 

Nếu không rõ ràng this trong ví dụ của bạn, trình biên dịch nghĩ rằng bạn đang sử dụng unary nhà điều hành + mà không được định nghĩa.