在 Kotlin 中是否有一种方法可以接受类型为 A 或 B 的参数?

4

假设我有 AB

data class A(val a: String, val common: String)
data class B(val b: String, val common: String)

我能否有一个可接受任意参数的方法,并在其中使用common?例如:

fun accept(val param: A|B) {
    println(param.common)
}

1
具体来说,你不能仅仅使用common的原因是AcommonBcommon无关。这两个属性可能拼写相同,但这并不重要;在Kotlin中,它们完全不同,因为它们之间没有继承关系。这种关系是所有答案以各种方式提供的。 - gidds
3个回答

4

密封类 基本上就是这样做的:

sealed class AorB (val common : String)
class A(val a: String, common: String) : AorB(common)
class B(val b: String, common: String) : AorB(common)

fun accept(param: AorB) {
    println(param.common)
    when(param) {
        is A -> println(param.a)
        is B -> println(param.b)
    }
}

fun main() {
    accept(A("a value", "common value")) 
    accept(B("b value", "common value")) 
}


不过,这并不适用于数据类。 - Adam Millerchip
1
啊,如果你将属性“open”设置为可访问的话,你可以使用数据类来完成它:sealed class AorB (open val common : String)。对于密封类加一分。 - Adam Millerchip
有没有一种方法可以在不使它们都继承该类的情况下完成这个操作? - orirab
如果我正确理解了你的问题 - 不行。继承可以通过接口,就像Adam建议的那样,或者封闭类来实现,这是使A|B工作的关键。 - David Soroko
@orirab,您可以使用函数重载来实现不同的方式,避免继承。我更新了我的答案。 - Adam Millerchip
事实是,我有多个类似的字段,似乎继承对我的用例来说是更好的选择... - orirab

3

如果你让它们都实现一个共同的接口,并将该接口用作参数类型,则可以做到这一点:

interface HasCommon {
    val common: String
}

data class A(val a: String, override val common: String) : HasCommon
data class B(val b: String, override val common: String) : HasCommon

fun accept(param: HasCommon) {
    println(param.common)
}

fun main() {
    accept(A("a", "a"))
    accept(B("b", "b"))
}

输出:

a
b

另外一种更加函数化的方式是为每个类型定义多个版本的 accept,并将共同的功能抽象出来:

data class A(val a: String, val common: String)
data class B(val b: String, val common: String)

fun accept(a: A) = printCommon(a.common)
fun accept(b: B) = printCommon(b.common)

fun printCommon(common: String) = println(common)

fun main() {
    accept(A("a", "a"))
    accept(B("b", "b"))
}

1
这个可以工作,但是将参数称为“common”纯粹是为了美观。它们与“a”或“b”一样没有更多的共同点。 - David Soroko
假设你在谈论第二个例子。第一个是由接口强制执行的。虽然我现在更喜欢第二个。你可以通过将它们作为扩展函数来强制执行:fun A.printCommon() = printCommon(common) - Adam Millerchip

1
继承被认为是解决这个问题的方法。
毕竟,接受任何一种都意味着你不能调用它们的任何特定方法,除非你将它们转换。
这将与在Kotlin中接受“Any”相同。
一种解决方法是定义两种方法,其中一个方法可以在转换后调用另一个方法。
或者你让类继承,但你正在使用数据类,所以我假设你已经知道它对于它们来说不容易实现。
数据类继承的一种解决方法是this

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接