【问题标题】:Generics in constructors in KotlinKotlin 构造函数中的泛型
【发布时间】:2020-02-28 16:40:13
【问题描述】:

我可以在 Java 中做到这一点:

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

Foo 的构造函数中,arg 的类型是扩展Bar 并实现Baz。这是在不向Foo(即class Foo&lt;T extends Bar &amp; Baz&gt;)添加类型参数的情况下完成的。我如何在 Kotlin 中做同样的事情?类似:

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

更新:我想添加更多上下文,我在 Android 中使用 dagger,这需要我这样做:

@ContributesAndroidInjector
abstract fun Foo(): Foo

当我这样做时,@ContributesAndroidInjector methods cannot return parameterized types 失败:

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

这就是为什么添加类型参数(类似于ysakhno 的答案)不是解决方案的原因。

【问题讨论】:

  • 所以本质上你需要一个默认构造函数(除了带参数的构造函数)?
  • 只是为了理解用例:如果类没有类型参数,你将如何使用构造函数的参数化参数?
  • @ContributesAndroidInjector 通常用于 Android 清单中列出的类,这些类没有构造函数参数。你想用这种方式解决什么问题?
  • 我更新了我的答案以满足您的特定需求。希望对您有所帮助。
  • 我的建议是简单地使其成为工厂方法而不是构造函数。

标签: android kotlin dagger


【解决方案1】:

您可以在 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)
}

更新:如果你真的需要一个没有泛型类型参数的类,而且还需要一个泛型“构造函数”,我认为 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)
}

【讨论】:

  • 了解投反对票的原因会很有帮助。我相信答案是正确的,并且我相信该示例有效,因为我在发布之前对其进行了测试。
  • 感谢您的回答,这是我尝试的解决方案之一,请参阅更新后的问题。 (我没有投反对票)
【解决方案2】:

你可以使用:


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 块上作为主构造函数的主体。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-11
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多