2010-09-22 32 views
19

Hãy xem xét các lớp sau đây viết bằng Java:Scala thành viên lớp và các thông số constructor tên đụng độ

class NonNegativeDouble { 
    private final double value; 
    public NonNegativeDouble(double value) { 
     this.value = Math.abs(value); 
    } 
    public double getValue() { return value; } 
} 

Nó định nghĩa một lĩnh vực thức gọi value đó được khởi tạo trong constructor, bằng cách lấy thông số của nó được gọi là giống nhau và áp dụng một chức năng cho nó.

Tôi muốn viết một cái gì đó tương tự như nó trong Scala. Lúc đầu, tôi đã cố gắng:

class NonNegativeDouble(value: Double) { 
    def value = Math.abs(value) 
} 

Nhưng trình biên dịch phàn nàn: lỗi: quá tải nhu cầu giá trị phương pháp cho kết quả loại

Rõ ràng là trình biên dịch cho rằng sự biểu hiện value bên trong biểu Math.abs(value) đề cập đến phương pháp này được xác định . Do đó, phương thức được định nghĩa là đệ quy, vì vậy tôi cần nêu rõ kiểu trả về của nó. Vì vậy, các mã tôi đã viết không làm những gì tôi mong đợi nó để làm: Tôi muốn value bên trong Math.abs(value) để tham khảo các tham số constructor value, và không để phương pháp được xác định. Nó giống như trình biên dịch ngầm thêm một số this. đến Math.abs(this.value).

Thêm val hoặc var (hoặc private ... biến thể) vào tham số hàm tạo dường như không hữu ích.

Vì vậy, câu hỏi của tôi là: tôi có thể xác định thuộc tính có cùng tên với tham số hàm tạo, nhưng có thể có giá trị khác không? Nếu vậy, làm thế nào? Nếu không, tại sao?

Cảm ơn!

Trả lời

16

Không, bạn không thể. Trong Scala, các tham số của hàm tạo là các thuộc tính, do đó không có nghĩa lý gì khi định nghĩa lại chúng.

Các giải pháp, một cách tự nhiên, là sử dụng một tên khác:

class NonNegativeDouble(initValue: Double) { 
    val value = Math.abs(initValue) 
} 

Được sử dụng như thế này, initValue sẽ không là một phần của các trường hợp tạo ra. Tuy nhiên, nếu bạn sử dụng nó trong một tờ khai def hoặc mẫu phù hợp, thì nó sẽ trở thành một phần của mọi cá thể của lớp.

+8

Một hàm tạo không được tạo thành một thuộc tính trừ khi đó là một lớp chữ thường hoặc được chú thích với val hoặc var. Nó có sẵn để sử dụng bất cứ nơi nào bên trong định nghĩa lớp mặc dù. –

+1

Có bất kỳ loại quy ước đặt tên nào của các tham số hàm tạo trong các trường hợp như vậy không? –

+2

@Bruno - Có một số quy ước đặt tên; Cá nhân tôi thích cái mà trong đó 0 được nối thêm vào tên, vì số 0 đó ngụ ý điểm bắt đầu và nó ngắn gọn. (Đôi khi gạch dưới đôi khi được thêm vào hoặc nối thêm, nhưng cá nhân tôi cảm thấy có rất nhiều dấu gạch dưới nằm xung quanh.) –

2

Bạn có thể xem xét lĩnh vực tham số

class NonNegativeDouble(val value: Double, private val name: String){ 
    if (value < 0) throw new IllegalArgumentException("value cannot be negative") 
    override def toString = 
    "NonNegativeDouble(value = %s, name = %s)" format (value, name) 
} 

val tom = "Tom" 
val k = -2.3 

val a = new NonNegativeDouble(k.abs, tom) 
a: NonNegativeDouble = NonNegativeDouble(value = 2.3, name = Tom) 

a.value 
res13: Double = 2.3 

a.name 
<console>:12: error: value name in class NonNegativeDouble cannot be accessed in NonNegativeDouble 
    a.name 

val b = new NonNegativeDouble(k, tom) 
java.lang.IllegalArgumentException: value cannot be negative 
... 

Đó là định nghĩa lĩnh vực và các thông số với cùng tên "giá trị", "tên". Bạn có thể thêm từ bổ nghĩa như tư nhân ...

+1

Bạn có ý nghĩa gì bởi "trường tham số"? Và trong ví dụ của bạn, chúng ta có thể dễ dàng khởi tạo 'NonNegativeDouble', giá trị của nó thực sự sẽ trả về giá trị âm gấp đôi. – Rogach

+0

@Rogach với "trường tham số", bạn có thể tạo các trường có cùng tên với tên thông số trong hàm tạo. Tôi đã cải thiện ví dụ của mình. –

4

@Daniel C. Sobral

class NonNegativeDouble(initValue: Double) { 
    val value = Math.abs(initValue) 
} 

mã của bạn là đúng, nhưng "thông số nhà xây dựng là tài sản", điều này là không đúng.

A post from the official site said,

A parameter such as class Foo(x : Int) is turned into a field if it is referenced in one or more methods

Và Martin trả lời khẳng định sự thật của nó:

That's all true, but it should be treated as an implementation technique. That's why the spec is silent about it.

Vì vậy, thông thường, chúng ta vẫn có thể điều trị các thông số nhà xây dựng chính như tham số phương pháp thông thường, nhưng khi các thông số được tham chiếu bởi bất kỳ của các phương thức, trình biên dịch sẽ khéo léo biến nó thành một trường riêng.

Nếu có bất kỳ tham số chính thức nào đứng trước val, trình biên dịch sẽ tạo ra một định nghĩa getter tự động.if var, tạo ra một setter bổ sung. xem phần tiết kiệm ngôn ngữ 5.3.

Đó là tất cả về các tham số hàm tạo chính.

0

Trong trường hợp của case classes nó nên là:

case class NonNegativeDouble(private val initValue: Double) { 
    val value = Math.abs(initValue) 
    def copy(value: Double = this.value) = NonNegativeDouble(value) 
} 

Việc thực hiện copy là cần thiết để ngăn chặn các phiên bản sintesized của trình biên dịch rằng sẽ ràng buộc đối số initValue.

Tôi mong rằng trình biên dịch đủ thông minh để không giữ lại «khoảng trống thừa» cho initValue. Tôi chưa xác minh hành vi này.

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