2016-12-12 15 views
5

Tôi có đoạn mã sau sử dụng Generics:Generics Kotlin của: Kiểu không khớp trong tham số bản đồ chung

abstract class Event(val name: String) 

interface ValueConverter<E : Event> { 

    fun convert(event: E): Float 

    fun getEventClass(): Class<E> 

} 

class ValueConverters { 

    private val converters = HashMap<String, ValueConverter<Event>>() 

    fun <E : Event> register(converter: ValueConverter<E>) { 
     converters.put(converter.getEventClass().name, converter) 
    } 

    fun unregister(eventClass: Class<Event>) { 
     converters.remove(eventClass.name) 
    } 

    fun <E : Event> convert(event: E): Float { 
     return converters[event.javaClass.name]?.convert(event) ?: 0.0f 
    } 

    fun clear() { 
     converters.clear() 
    } 

} 

Nhưng trên dòng này:

converters.put(converter.getEventClass().name, converter) 

nó mang lại một lỗi:

Type mismatch. Expected ValueConverter<Event>. Found ValueConverter<E>.

Tôi cũng đã thử một số nội dung như sau:

class ValueConverters { 

    private val converters = HashMap<String, ValueConverter<Event>>() 

    fun register(converter: ValueConverter<Event>) { 
     converters.put(converter.getEventClass().name, converter) 
    } 

    fun unregister(eventClass: Class<Event>) { 
     converters.remove(eventClass.name) 
    } 

    fun convert(event: Event): Float { 
     return converters[event.javaClass.name]?.convert(event) ?: 0.0f 
    } 

    fun clear() { 
     converters.clear() 
    } 

} 

Nhưng vấn đề là khi gọi ValueConverters.register() với một cái gì đó như:

class SampleEvent1 : Event(name = SampleEvent1::class.java.name) 

class SampleValueConverter1 : ValueConverter<SampleEvent1> { 

    override fun convert(event: SampleEvent1): Float = 0.2f 

    override fun getEventClass(): Class<SampleEvent1> = SampleEvent1::class.java 

} 

converters.register(converter = SampleValueConverter1()) 

Nó cũng cung cấp cho các sai lầm loại không phù hợp tương tự.

Làm cách nào để khai báo các generics để tôi có thể sử dụng bất kỳ lớp nào triển khai ValueConverter và chấp nhận bất kỳ lớp nào mở rộng Sự kiện?

Trả lời

8

Lỗi này là trên dòng này:

private val converters = HashMap<String, ValueConverter<Event>>()

Các giá trị của bản đồ này được giới hạn cho ValueConverter<Event>. Vì vậy, nếu bạn có một lớp

class FooEvent : Event

và chuyển đổi giá trị:

ValueConverter<FooEvent>,

bạn không thể lưu trữ mà chuyển đổi giá trị trong bản đồ của bạn. Điều bạn thực sự muốn là loại chiếu sao *.

private val converters = HashMap<String, ValueConverter<*>>()

Bây giờ bạn có thể đặt bất cứ điều gì chuyển đổi giá trị trong bản đồ.


Tuy nhiên, đây phát hiện ra một vấn đề khác: Làm thế nào để

fun <E : Event> convert(event: E): Float

biết những gì loại generic của bộ chuyển đổi trở lại trong bản đồ là gì? Sau khi tất cả, bản đồ có thể chứa nhiều bộ chuyển đổi cho các loại sự kiện khác nhau!

IntelliJ kịp phàn nàn:

Out-projected type 'ValueConverter<*>?' prohibits the use of 'public abstract fun convert(event: E): Float defined in ValueConverter'.

Nhưng bạn đã biết kiểu generic vì chính bản đồ của bạn là tên của tham số kiểu chung chung!

Vì vậy, chỉ đơn giản là đúc các giá trị được trả về bởi bản đồ với lực:

@Suppress("UNCHECKED_CAST") 
fun <E : Event> convert(event: E): Float { 
    val converter = converters[event.javaClass.name] ?: return 0.0f 
    return (converter as ValueConverter<E>).convert(event) 
} 

Nếu bạn tò mò tại sao các trình biên dịch không phàn nàn về chức năng chuyển đổi của bạn trước đó: Ghi như thế nào bản đồ của bạn chỉ có thể giữ ValueConverter<Event> và chỉ có lớp đó? Điều này có nghĩa là trình biên dịch biết bạn có thể vượt qua bất kỳ lớp con nào của Event vào trình chuyển đổi này. Khi bạn thay đổi thành một loại sao chiếu, trình biên dịch không biết liệu đây có phải một ValueConverter<FooEvent>, hoặc một ValueConverter<BazEvent>, vv - làm cho chức năng chữ ký có hiệu lực của bộ chuyển đổi được đưa ra trong bản đồ của bạn convert(event: Nothing):

vì không có gì là một đầu vào hợp lệ.

+0

Cảm ơn! Nó hoạt động. –

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