Обобщения в конструкторах Kotlin - PullRequest
1 голос
/ 28 февраля 2020

Я могу сделать это в Java:

public <T extends Bar & Baz> Foo(T arg) { ... }

В конструкторе Foo, arg набирается так, что он расширяет Bar и реализует Baz. Это делается без добавления параметра типа в Foo (т.е. class Foo<T extends Bar & Baz>). Как мне сделать то же самое в Kotlin? что-то вроде:

constructor<T>(arg: T) where T : Bar, T : Baz { ... }

Обновление: Я хотел бы добавить больше контекста, я использую кинжал в Android, который требует от меня сделать это:

@ContributesAndroidInjector
abstract fun Foo(): Foo

Не удается выполнить команду @ContributesAndroidInjector methods cannot return parameterized types, когда я делаю это:

@ContributesAndroidInjector
abstract fun Foo(): Foo<*>

Вот почему добавление параметра типа (аналогично ответу ysakhno) не является решением.

Ответы [ 2 ]

0 голосов
/ 28 февраля 2020

Вы можете сделать это в Kotlin, хотя и с основным конструктором. Вот пример:

interface Baz

open class Bar

class Foo<T>(arg: T) where T : Bar, T : Baz {
    init {
        println(arg)
    }
}

class BarBaz : Bar(), Baz

fun main() {
    val bar = Bar()
    val baz = object : Baz {}
    val bb = BarBaz()

    val fooBarBaz = Foo(bb) // This one works
    val fooBar = Foo(bar) // Although this one does not (bar does not implement Baz)
    val fooBaz = Foo(baz) // This one does not work also (baz does not extend Bar)
}

ОБНОВЛЕНИЕ: Если вам действительно нужен класс без параметра типа generi c, но при этом также имеется конструктор generi c ' В некотором роде, я не думаю, что в Kotlin есть другой способ, кроме как прибегнуть к сопутствующему объекту. Вот так:

interface Baz

open class Bar

class Foo {

    companion object {
        fun <T> create(arg: T): Foo where T : Bar, T : Baz {
            val inst = Foo() // Note that class Foo is not parameterized
            println(arg)
            // Do something else with the instance here, if needed
            return inst
        }
    }
}

class BarBaz : Bar(), Baz

fun main() {
    val bar = Bar()
    val baz = object : Baz {}
    val bb = BarBaz()

    val fooBarBaz = Foo.create(bb) // This one still works
    // The following two do not work for the same reasons as with parameterized class
    val fooBar = Foo.create(bar)
    val fooBaz = Foo.create(baz)
}
0 голосов
/ 28 февраля 2020

Вы можете использовать:


class Foo<T : Any>(arg: T) { // ": Any" forces the type to be non nullable

    // Arg is a "constructor" parameter so you can access it on the init block
    init {
        println(arg::class)
    }
}

Любой конструктор в классе Kotlin должен вызывать другой, и, наконец, он будет вызывать главный конструктор класса (который определен в самом объявлении класса.

Вы можете думать об объявлении класса как об объявлении основного конструктора, а о блоке init как о теле основного конструктора.

...