kotlin 中数据 class 的流畅方法

Fluent methods for data class in kotlin

我们熟悉在 java 和其他编程语言中调用方法的流畅接口。例如:

Picasso.with(this).load(url).into(imageView);

这可以通过 setter 方法实现 return 所需类型的对象。

public Picasso with(Context context)
{
    this.context = context;
    return this;
}

public X load(String url)
{
    this.url = url;
    return this;
}

public Y load(ImageView imageView)
{
    this.imageView = imageView;
    return this;
}

我正在尝试对 kotlin 数据做同样的事情 类 但遗憾的是我找不到一种方法来覆盖我在其中使用的 setter 方法可以 return 该对象的新实例。

当我尝试强行覆盖 setter 方法时出现编译器错误。

关于可以做什么的任何想法,以便我可以调用流畅的接口或至少改变 setter 的工作方式 可能是这样的

data class CorruptOfficeAccount(.....){
     override fun addCollectedFee(Long money) :CorruptOfficeAccount {
     this.money = money/5
    }
}

这样我就可以打电话给

CorrutOfficeAccount(....).method1().addCollectedFee(20000).method3()

如果除了 Name 之外不需要 return 任何东西,您可以这样做:

data class Name(var firstName: String, var lastName: String)

fun foo() {
    val name = ...
    name.apply {
        firstName = ...
        lastName = ...
    }
}

或另一个例子:

CorrutOfficeAccount(....).apply {
    method1()
    addCollectedFee(20000)
    method3()
}

传递给apply的函数内部(花括号里面的东西),this是对象apply被调用,这使得可以引用成员函数和firstName 之类的属性而不写 name.firstName.

如果您对此不满意:不可能制作实际的 setter return 东西,但是您当然可以定义一个具有不同名称的方法并制作 return 东西.

为了在 Kotlin 中访问属性,我们不使用 getter 和 setter 函数,虽然您可以重写它们的 setter 以赋予它们自定义行为,但您可以不要让它们 return 任何东西,因为调用它们是一个赋值,这不是 Kotlin 中的表达式。例如,这不起作用:

var x = 1
var y = (x = 5) // "Assigments are not expressions, and only expressions are allowed in this context"

您可以做的是定义设置它们的其他方法,然后 return 调用它们的实例。例如:

data class Name(var firstName: String = "", var lastName: String  =  "") {
    fun withLastName(lastName: String): Name {
        this.lastName = lastName
        return this
    }
}

val name = Name(firstName = "Jane") 
name.withLastName("Doe").withLastName("Carter")

请注意,如果您将此方法命名为 setLastName,那么在使用 Java 中的 class 时会遇到问题,因为 lastName 属性当您编写 Java 代码时,通过名为 setLastName 的方法已经可见。

虽然在 Kotlin 中更常见的解决方案是使用标准库中的 apply 替换流畅的构建器,正如 Christian 的回答中所描述的那样。

感谢 Zsmb13 和 Christin 的回答,但如果有人想使用不可变字段,我有另一个解决方案

data class Foo(val fooString: String = "", val fooInt: Int = 0) {
    fun increaseTwo() = copy(fooInt = fooInt + 2)
    fun increaseThree() = copy(fooInt = fooInt + 3)
}

你可以像这样使用它

println( Foo("foo",2).increaseTwo().increaseThree())

输出:

Foo(fooString=foo, fooInt=7)