2017-10-22 10 views
6

Tôi có giao diện chứa mảng (hoặc danh sách) của T và một số siêu dữ liệu.Kotlin generics Array <T> kết quả trong "Không thể sử dụng T làm tham số kiểu được sửa đổi. Sử dụng lớp thay thế" nhưng Danh sách <T> không

interface DataWithMetadata<T> { 
    val someMetadata: Int 
    fun getData(): Array<T> 
} 

Nếu tôi viết thực hiện đơn giản nhất của giao diện, tôi nhận được một lỗi biên dịch trên emptyArray(): "Không thể sử dụng T như một tham số kiểu reified Sử dụng một lớp học để thay thế.."

class ArrayWithMetadata<T>(override val someMetadata: Int): DataWithMetadata<T> { 
    private var myData: Array<T> = emptyArray() 

    override fun getData(): Array<T> { 
     return myData 
    } 

    fun addData(moreData: Array<T>) { 
     this.myData += moreData 
    } 
} 

Tuy nhiên, nếu tôi thay đổi cả giao diện và thực hiện vào một danh sách, tôi không có vấn đề thời gian biên dịch:

interface DataWithMetadata<T> { 
    val someMetadata: Int 
    fun getData(): List<T> 
} 

class ListWithMetadata<T>(override val someMetadata: Int): DataWithMetadata<T> { 
    private var myData: List<T> = emptyList() 

    override fun getData(): List<T> { 
     return myData 
    } 

    fun addData(moreData: Array<T>) { 
     this.myData += moreData 
    } 
} 

tôi nghi ngờ có một số bài học thú vị trong Generics Kotlin bên trong vấn đề của tôi . Bất cứ ai có thể cho tôi biết những gì trình biên dịch đang làm theo mui xe và tại sao Array không nhưng Danh sách không? Có một cách thành ngữ để làm cho việc thực hiện Array biên dịch trong bối cảnh này?

Câu hỏi thưởng: Lý do duy nhất tôi đạt được cho Array over List là tôi thường thấy các nhà phát triển Kotlin ưu tiên Mảng. Đây có phải là trường hợp không, và nếu có thì tại sao?

Trả lời

5

Nhìn vào tờ khai của emptyArray() trong stdlib Kotlin (JVM), chúng tôi nhận thấy các thông số reified loại:

public inline fun <reified @PureReifiable T> emptyArray(): Array<T> 

Tham số reified loại có nghĩa là bạn có quyền truy cập vào các lớp của T tại thời gian biên dịch và có thể truy cập nó như T::class. Bạn có thể đọc thêm về các thông số loại reified trong Kotlin reference. Vì Array<T> biên dịch sang java T[], chúng ta cần phải biết loại tại thời gian biên dịch, do đó tham số reified. Nếu bạn cố gắng viết một chức năng emptyArray() mà không có từ khóa reified, bạn sẽ nhận được một lỗi biên dịch:

fun <T> emptyArray() : Array<T> = Array(0, { throw Exception() }) 

Cannot use T as a reified type parameter. Use a class instead.


Bây giờ, chúng ta hãy nhìn vào việc thực hiện các emptyList():

public fun <T> emptyList(): List<T> = EmptyList 

Triển khai này không cần tham số T. Nó chỉ trả về đối tượng nội bộ EmptyList, chính nó kế thừa từ List<Nothing>. Loại kotlin Nothing là kiểu trả về của từ khóa throw và là giá trị không bao giờ tồn tại (reference). Nếu phương thức trả về Nothing, tương đương với việc ném ngoại lệ tại địa điểm đó. Vì vậy, chúng ta có thể sử dụng an toàn Nothing ở đây bởi vì mọi lúc chúng ta sẽ gọi EmptyList.get() trình biên dịch biết rằng điều này sẽ trả về một ngoại lệ.


Bonus câu hỏi:

Đến từ Java và C++, tôi đang sử dụng để ArrayList hoặc std::vector là xa dễ dàng hơn để sử dụng mảng. Tôi sử dụng kotlin bây giờ trong một vài tháng và tôi thường không thấy sự khác biệt lớn giữa các mảng và danh sách khi viết mã nguồn.Cả hai đều có rất nhiều chức năng mở rộng hữu ích hoạt động theo cách tương tự. Tuy nhiên, trình biên dịch Kotlin xử lý các mảng và danh sách rất khác nhau, vì khả năng tương tác Java là rất quan trọng đối với nhóm Kotlin. Tôi thường thích sử dụng danh sách, và đó là những gì tôi muốn giới thiệu trong trường hợp của bạn quá.

2

Vấn đề là, rằng các loại nguyên tố chung của một Array phải được biết tại thời gian biên dịch, được chỉ định bởi các tham số reified loại ở đây, như đã thấy trong phần khai báo:

public inline fun <reified @PureReifiable T> emptyArray(): Array<T> 

Nó chỉ có thể tạo các mảng bê tông như Array<String> hoặc Array<Int> nhưng không phải là loại Array<T>.

Trong số answer này, bạn có thể tìm thấy một số cách giải quyết. Hy vọng bạn tìm thấy một cách phù hợp.

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