Tôi muốn thêm phương thức vào loại được cài sẵn (ví dụ: Double), để tôi có thể sử dụng toán tử infix
. Điều đó có thể không?Có thể thêm phương thức vào kiểu tích hợp trong Scala không?
Trả lời
Có và không. Có, bạn có thể làm cho nó dường như giống như bạn đã thêm phương thức vào double
. Ví dụ:
class MyRichDouble(d: Double) {
def <>(other: Double) = d != other
}
implicit def doubleToSyntax(d: Double) = new MyRichDouble(d)
Mã này thêm <>
điều hành trước đó không có sẵn cho bất kỳ đối tượng kiểu Double
. Vì vậy, miễn là phương pháp doubleToSyntax
là trong phạm vi sao cho nó có thể được gọi mà không cần trình độ chuyên môn, sau đây sẽ làm việc:
3.1415 <> 2.68 // => true
Các "không" một phần của câu trả lời xuất phát từ thực tế là bạn không thực sự thêm bất cứ điều gì đến lớp học Double
. Thay vào đó, bạn đang tạo chuyển đổi từ Double
thành loại mới xác định phương thức bạn muốn. Đây có thể là một kỹ thuật mạnh hơn nhiều so với các lớp mở được cung cấp bởi nhiều ngôn ngữ động. Nó cũng xảy ra hoàn toàn an toàn kiểu. :-)
Một số hạn chế bạn nên biết:
- Kỹ thuật này không cho phép bạn để loại bỏ hoặc xác định lại phương pháp hiện có, chỉ cần thêm những cái mới
- Phương pháp chuyển đổi ngầm (trong trường hợp này,
doubleToSyntax
) hoàn toàn phải nằm trong phạm vi cho phương pháp tiện ích mong muốn có sẵn
Tự nhiên, ngầm định c các đảo ngược được đặt trong các đối tượng đơn lẻ và được nhập (ví dụ: import Predef._
) hoặc trong các đặc điểm và được kế thừa (ví dụ: class MyStuff extends PredefTrait
).
Nhẹ sang một bên: "toán tử kết nối" trong Scala thực ra là phương pháp. Không có phép thuật nào liên quan đến phương thức <>
cho phép nó được nhúng, trình phân tích cú pháp đơn giản chấp nhận nó theo cách đó. Bạn cũng có thể sử dụng "phương thức thông thường" làm toán tử nếu bạn muốn. Ví dụ: lớp Stream
xác định phương thức take
lấy một tham số Int
duy nhất và trả lại Stream
mới. Điều này có thể được sử dụng theo cách sau:
val str: Stream[Int] = ...
val subStream = str take 5
Khái niệm str take 5
là nghĩa đen giống hệt nhau để str.take(5)
.
Tính năng này đã có ích để thực hiện một ước lượng lỗi lớp biểu diễn:
object errorEstimation {
class Estimate(val x: Double, val e: Double) {
def + (that: Estimate) =
new Estimate(this.x + that.x, this.e + that.e)
def - (that: Estimate) =
new Estimate(this.x - that.x, this.e + that.e)
def * (that: Estimate) =
new Estimate(this.x * that.x,
this.x.abs*that.e+that.x.abs*this.e+this.e*that.e)
def/(that: Estimate) =
new Estimate(this.x/that.x,
(this.x.abs*that.e+that.x.abs*this.e)/(that.x.abs*(that.x.abs-that.e)))
def +- (e2: Double) =
new Estimate(x,e+e2)
override def toString =
x + " +- " + e
}
implicit def double2estimate(x: Double): Estimate = new Estimate(x,0)
implicit def int2estimate(x: Int): Estimate = new Estimate(x,0)
def main(args: Array[String]) = {
println(((x: Estimate) => x+2*x+3*x*x)(1 +- 0.1))
// 6.0 +- 0.93
println(((x: Estimate) => (((y: Estimate) => y*y + 2)(x+x)))(1 +- 0.1))
// 6.0 +- 0.84
def poly(x: Estimate) = x+2*x+3/(x*x)
println(poly(3.0 +- 0.1))
// 9.33333 +- 0.3242352
println(poly(30271.3 +- 0.0001))
// 90813.9 +- 0.0003
println(((x: Estimate) => poly(x*x))(3 +- 1.0))
// 27.037 +- 20.931
}
}
Đó là thực sự kinda gọn gàng. :) –
Bạn có thể sử dụng cú pháp 'ngầm class' để đơn giản hóa này một chút. – lmm