【问题标题】:What does "with" mean in Kotlin?Kotlin 中的“with”是什么意思?
【发布时间】:2017-08-25 01:43:02
【问题描述】:

我已经阅读了 3 次关于它的文档,但我仍然不知道它的作用。有人可以 ELI5(像我五岁一样解释)吗?以下是我的使用方法:

fun main(args: Array<String>) {
    val UserModel = UserModel()
    val app = Javalin.create().port(7000).start()

    with (app) {
        get("/users") {
            context -> context.json(UserModel)
        }
    }
}

【问题讨论】:

  • 哇,你的问题让我意识到没有很好的文档说明 with 的原因 - 作为一个函数,而不是关键字 - 真正有效!所以我写了一个问题并以相同的类型回答它,也许它会给已经存在的答案增加一些价值。见:What is a “receiver” in Kotlin?

标签: kotlin


【解决方案1】:

with 用于访问对象的成员和方法,而不必每次访问都引用该对象。它(主要)用于缩写您的代码。在构造对象的时候经常用到:

// Verbose way, 204 characters:
var thing = Thingummy()
thing.component1 = something()
thing.component2 = somethingElse()
thing.component3 = constantValue
thing.component4 = foo()
thing.component5 = bar()
parent.children.add(thing)
thing.refcount = 1

// Terse way, 182 characters:
var thing = Thingummy()
with(thing) {
  component1 = something()
  component2 = somethingElse()
  component3 = constantValue
  component4 = foo()
  component5 = bar()
  parent.children.add(this)
  refcount = 1
}

【讨论】:

  • 这也是指出这鼓励不变性的好时机;第二个 var thing 应该变成 val thing 并保证它永远不会改变,除非你想要它改变
  • 简单到重点。我个人认为,这样的答案比冗长的答案更值得关注。正如 PO 自己明确要求的“像我五岁一样解释”。不能破坏此线程中的其他答案,但可以说一件事能够简化某事意味着您掌握了要点
  • @Supuhstar 不变性与它无关。 val 仅仅意味着,你不能重新分配。这并不意味着您不能更改状态。如果第二个thing可以是val,那么第一个也可以
  • 这也是真的,@FrankNeblung。我希望 Kotlin 具有与 Swift 对值类型的 let 关键字相同的属性。
  • 我认为这个例子不会从with 块返回实际的Thingummy 对象。 this 应该是 lambda 的最后一行。
【解决方案2】:

documentation 说:

inline fun &lt;T, R&gt; with(receiver: T, block: T.() -&gt; R): R (source)

以给定的接收者为接收者调用指定的功能块并返回其结果。

我认为它是调用一个函数(block),其中thisblock 的范围内是receiver。 无论block 返回什么都是返回类型。

本质上是调用提供隐式this 并可以从中返回任何结果的方法。

下面是一个例子来演示:

val rec = "hello"
val returnedValue: Int = with(rec) {
  println("$this is ${length}")
  lastIndexOf("l")
}

本例中的rec 是函数调用的接收者 - 在block 范围内的this$lengthlastIndexOf 都在接收器上调用。

可以看到返回值是一个Int,因为这是body中的最后一个方法调用——也就是签名的泛型类型参数R

【讨论】:

  • 所以它只是一个工具,用来说明你想在什么范围内?
  • @VladyVeselinov 基本上是的。还有一些其他的作用域函数可以帮助您正确地编写更清晰的代码。您可以在yole/kotlin-style-guide GitHub repository 中看到一些关于一般使用模式的示例和讨论。
【解决方案3】:

with的定义:

inline fun <T, R> with(receiver: T, block: T.() -> R): R (source)

实际上它的实现很简单:blockreceiver 上执行,适用于任何类型:

receiver.block() //that's the body of `with`

这里要提的是参数类型T.() -&gt; R: 它被称为function literal with receiver。它实际上是一个 lambda,无需任何额外的限定符即可访问接收者的成员。

在您的示例中,with 接收者 appcontext 以这种方式访问​​。

除了withapply 等stdlib 函数之外,此功能使Kotlin 非常适合编写领域特定语言,因为它允许创建您可以访问某些功能的范围。

【讨论】:

    【解决方案4】:
    val citizen2 = Citizen("Tom", 24, "Washington")
    
    val age = with(citizen2) {
        println("$name -  $age  $residence ")
        age = this.age + age
        residence = "Florida"
        age+10 // returns 58
    }
    println("${citizen2.name} -  ${citizen2.age} - $age - ${citizen2.residence}  ")
    
    data class Citizen(var name: String, var age: Int, var residence: String)
    

    输出:

    Tom -  24  Washington 
    Tom -  48 - 58 - Florida
    

    请注意:

    • 我们可以通过 this.ageage 访问公民(接收者对象)的年龄属性
    • with() 返回的 lambda 中的最后一行(本例中为 age+10)。

    【讨论】:

      【解决方案5】:

      With 用于将多个操作应用于对象或访问对象的方法,例如在这个例子中,我们正在访问 String 的 capitalize() 扩展方法

      data class Person(val name:String)
      fun main(){
         val person = Person("john doe")
          with(person) {
             println(name.capitalize()) // output John Doe
          }
      
      }
      
      

      with 是一个高阶函数。在这里,我们说的是人名调用大写()。我们实际上并不需要“this”,因为它是隐含的,可以删除

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-09
        • 1970-01-01
        • 1970-01-01
        • 2017-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多