这是标准的Kotlin功能(据我所知)
inline fun<T> with(t: T, body: T.() -> Unit) { t.body() }
但是,任何人都可以用简单的英文写下签名的意思吗?它是T的通用函数,第一个参数为“t” T型和第二种,功能型“体”,接受????的功能什么都不返回(单位)
我看到这个符号Something。() - &gt;有些东西经常使用,即Anko:
inline fun Activity.coordinatorLayout(init: CoordinatorLayout.() -> Unit) = ankoView({ CoordinatorLayout(it) },init)
但我不认为它在任何地方被解释过。()意味着......
答案 0 :(得分:25)
T.() -> Unit
是带接收器的扩展函数类型。
除普通功能外,Kotlin还支持扩展功能。这种功能与普通功能的不同之处在于它具有接收器类型规范。这是一个通用的T.
部分。
扩展函数中的this
关键字对应于接收者对象(在点之前传递的对象),因此您可以直接调用其方法(从父作用域引用this
仍然是可能with qualifiers)。
函数with
是标准函数,是的。这是当前的代码:
/**
* Calls the specified function [f] with the given [receiver] as its receiver and returns its result.
*/
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
因此它是T
和R
的通用函数,第一个参数是“{1}}类型的接收者”,第二个是T
扩展函数类型,它扩展了{ {1}},返回由f
返回的T
类型。
例如,您可以像这样使用它:
R
请参阅此处的扩展功能文档:
kotlinlang.org/docs/reference/lambdas.html#extension-function-expressions
kotlinlang.org/docs/reference/extensions.html
<强>加了:强>
所以唯一有效的
定义的任何0参数函数with
是为T?
不是真的。在Kotlin function types and extension function types are unified中,它们可以互换使用。例如,我们可以传递String :: length,其中函数val threadInfoString = with (Thread.currentThread()) {
// isDaemon() & getPriority() are called with new property syntax for getters & setters
"${getName()}[isDaemon=$isDaemon,priority=$priority]"
}
是预期的。
f
类似(String) -> Int
&amp;的类型// map() expects `(String) -> Int`
// argument has type `String.() -> Int`
strings.map(String::length)
在背景方面是相同的 - 事实上,接收器是第一个参数。
因此,以下任何函数都适用于Thread.() -> String
参数:
(Thread) -> String
或者您可以像Thread.() -> String
一样使用function literal(fun main(args: Array<String>) {
val f1 = fun Thread.(): String = name
val f2 = fun Thread.() = name
val f3: Thread.() -> String = { name }
val f4: (Thread) -> String = { it.name }
val f5 = { t: Thread -> t.name }
val f6: (Thread) -> String = Thread::getNameZ
val f7: Thread.() -> String = Thread::getNameZ
val f8 = Thread::getNameZ
}
fun Thread.getNameZ() = name
),但只有在可以从上下文中推断出接收器类型时它才有效。
答案 1 :(得分:5)
这是另一个令人惊讶的概念,名为带有接收器的函数文字,它看起来与扩展函数类似,区别在于它具有 "receiver" 。
inline fun doSomethingWithInt(receiver: Int.() -> Unit) {
5.receiver() //Possible as receiver is Int type
receiver(5) //possible as receiver should be passed as first Argument
}
让我们分开吧
<强> (receiver: Int.() -> Unit)
强>
与常规lambda () -> Unit
有什么不同之处是它有接收器类型为 Int
与Extension函数类似,此接收器可以在 Int 类型
上调用 <强> 5.receiver()
强>
可以使用其调用(...)调用函数类型的值 运营商:
f.invoke(x)或只是f(x)。
如果值具有接收器类型,则应传递接收器对象 作为第一个论点。另一种调用函数值的方法 带接收器的类型是将它与接收器对象一起添加,就好像 该值是一个扩展函数:1.foo(2)
所以你也可以写 receiver(5)
现在我们可以编写 DSL样式代码了。我们来看看kotlin标准库函数Apply
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
正如您所见,apply是T的扩展函数,块将与接收器类型 T ,
一起使用由于T。() T将作为lambda中的第一个参数。
现在这里的块由函数体内的 block()调用,但你也可以写 this.block()或block(this)
在调用此lambda 后,我们将返回T的实例(调用apply的相同实例)
所以,我们在apply中做的是在参数中使用lambda,在调用它的同一个实例T上执行它,并返回相同的T实例
实施例
调用此函数将如下所示:
(StringBuilder("Hello ").apply({ append("Kotliner") }))
但是在kotlin中,如果lambda是最后一个参数,那么你可以简单地写funName({})
而不是写funName{}
。
所以上面的代码也可以写成
StringBuilder("Hello ").apply {
append("Kotliner")
append("! ")
}
看起来更清晰简洁。所以Kotlin这样就提供了像Groovy这样的DSL结构。
这是关于同一主题的very nice blog
答案 2 :(得分:0)
它被称为“带有接收器的函数文字”
函数类型可以有一个附加的接收器类型,该类型在符号中的点之前指定:类型A.(B)-> C表示可以在A的接收器对象上使用参数B调用的函数。并返回C值。带接收器的函数文字常与这些类型一起使用。
您可以在kotlin官方文档中找到答案:Function literals with receiver