2014-04-02 14 views
16

Tôi vừa mới bắt đầu khám phá ngôn ngữ Kotlin. Tôi đang đấu tranh với thừa kế, var & val và tác dụng phụ.Lỗi hoặc tính năng: Kotlin cho phép thay đổi 'val' thành 'var' trong thừa kế

Nếu tôi tuyên bố một đặc điểm A với một val x và ghi đè x trong AImpl nó có thể ghi đè lên nó như var (xem mã bên dưới). Ngạc nhiên là phương pháp print() trong A bị ảnh hưởng bởi việc gán lại x mặc dù x là một giá trị trong A. Đây có phải là một lỗi hoặc một tính năng?

Code:

trait A { 
    fun print() { 
    println("A.x = $x") 
    } 

    val x : Int; 
} 

class AImpl(x : Int) : A { 
    override var x = x; // seems like x can be overriden as `var` 
} 

fun main(args: Array<String>) { 

    val a = AImpl(2) 

    a.print() // A.x = 2 

    a.x = 3; // x can be changed 

    // even though print() is defined in trait A 
    // where x is val it prints x = 3 
    a.print() // A.x = 3 

} 

Tôi nhận thức được thực tế rằng nếu tôi xác định a với loại A rõ ràng nó không được phép thay đổi x:

val a = AImpl(2) : A 
a.x = 3 // ERROR: value x cannot be reassigned 

Nhưng như trường hợp chương trình đầu tiên , thừa kế có thể gây ra các tác dụng phụ rõ ràng không được dự định trong A. Làm cách nào để bảo vệ các giá trị không bị thay đổi bởi kế thừa?

Trả lời

26

Bạn có thể thực hiện valfinal, nghĩa là cấm ghi đè tất cả. Nếu bạn xác định val trong một lớp, nó là final theo mặc định.

Ngoài ra, nếu bạn cần phải ghi đè một val với một var, nhưng không muốn setter để được công khai, bạn có thể nói như vậy:

override var x = 1 
    private set 

Trọng một val với một varlà một tính năng . Nó tương đương với việc thêm một phương thức set trong khi trong superclass chỉ có một phương thức get. Và điều này khá quan trọng trong việc triển khai một số mẫu, chẳng hạn như giao diện chỉ đọc.

Không có cách nào để "bảo vệ" val của bạn khỏi bị ghi đè theo cách cho phép thay đổi đột biến khác với làm cho nó là , bởi vì val không có nghĩa là "tài liệu tham khảo bất biến", mà chỉ là "tài sản chỉ đọc". Nói cách khác, khi tính trạng của bạn A tuyên bố một val, điều đó có nghĩa là thông qua tham chiếu loại A khách hàng không thể viết số val này, không đảm bảo dự định khác hoặc thực sự có thể.

P.S. Dấu chấm phẩy là tùy chọn trong Kotlin, hãy bỏ qua chúng hoàn toàn

2

Tôi sẽ xem xét tính năng này, vì việc thay đổi val thành var áp đặt các hạn chế sử dụng yếu hơn và không thể vi phạm bất kỳ mã siêu lớp nào. Có thể quan sát tình huống tương tự với các công cụ sửa đổi chế độ hiển thị:

trait A { 
    protected fun print() { 
    ... 
    } 
} 

class AImpl: A { 
    public override fun print() { 
    ... 
    } 
} 

Trong ví dụ này, một số người xem xét kỹ thuật này như là một mẫu giả mạo.

Làm cách nào để bảo vệ các giá trị không bị thay đổi bởi kế thừa?

Trong kotlin bạn có thể xác định rõ ràng nếu bất kỳ thành viên lớp cụ thể nào có thể được ghi đè bởi lớp con bằng cách sử dụng công cụ sửa đổi open. Tuy nhiên, trong các đặc điểm, tất cả các thành viên đều mở theo mặc định. Giải pháp là thay thế đặc điểm bằng lớp, vì vậy bạn sẽ có thể kiểm soát thừa kế:

abstract class A { 
    fun print() { 
    ... 
    } 

    val x : Int = 2; 
} 

class AImpl(x : Int) : A() { 
    override var x = x // compilation error 
} 
Các vấn đề liên quan