这是标准的Kotlin功能(据我所知)
inline fun<T> with(t: T, body: T.() -> Unit) { t.body() }
Run Code Online (Sandbox Code Playgroud)
但是,任何人都可以用简单的英文写下签名的意思吗?它是T的通用函数,第一个参数"t"表示类型T,第二个参数是函数类型的"body",接受函数???? 没有返回(单位)
我看到这个符号Something.() - >有些东西经常使用,即对于Anko:
inline fun Activity.coordinatorLayout(init: CoordinatorLayout.() -> Unit) = ankoView({ CoordinatorLayout(it) },init)
Run Code Online (Sandbox Code Playgroud)
但我不认为它在任何地方被解释了.()意味着......
Art*_*pov 34
T.() -> Unit 是带接收器的扩展功能类型.
除了普通的功能,Kotlin还支持扩展功能.这种功能与普通功能的不同之处在于它具有接收器类型规范.这是一个通用的T.部分.
this扩展函数中的关键字对应于接收者对象(在点之前传递的对象),因此您可以直接调用其方法(使用限定符this仍然可以引用父作用域).
功能with是标准功能,是的.这是当前的代码:
/**
* Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#with).
*/
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
Run Code Online (Sandbox Code Playgroud)
所以它是一个泛型函数,T并且R,第一个参数是"接收器"的类型T,第二个f是扩展函数类型,它扩展T,返回类型,而类型R又返回with.
例如,您可以像这样使用它:
val threadInfoString = with (Thread.currentThread()) {
// isDaemon() & getPriority() are called with new property syntax for getters & setters
"${getName()}[isDaemon=$isDaemon,priority=$priority]"
}
Run Code Online (Sandbox Code Playgroud)
请参阅此处的扩展函数文档:
kotlinlang.org/docs/reference/lambdas.html#extension-function-expressions
kotlinlang.org/docs/reference/extensions.html
添加:
所以唯一有效的
f是为T定义的任何0参数函数?
并不是的.在Kotlin中,函数类型和扩展函数类型是统一的,因此它们可以互换使用.例如,我们可以在(String) -> Int期望函数的地方传递String :: length .
// map() expects `(String) -> Int`
// argument has type `String.() -> Int`
strings.map(String::length)
Run Code Online (Sandbox Code Playgroud)
类似于Thread.() -> String&的类型(Thread) -> String从背景方面来说是相同的 - 接收器实际上是第一个参数.
所以以下任何函数都适用于Thread.() -> String参数:
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
Run Code Online (Sandbox Code Playgroud)
或者您可以简单地使用函数literal({}),如示例中所示threadInfoString,但只有在可以从上下文中推断出接收器类型时它才有效.
这是另一个令人惊叹的概念,名为带有接收器的函数文字,它看起来与扩展函数类似,区别在于它具有"接收器".
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
}
Run Code Online (Sandbox Code Playgroud)
让我们分开吧
(receiver: Int.() -> Unit)
这与普通的lambda () -> Unit有什么不同,它有接收器的类型Int
所以类似于Extension函数,这个接收器可以在Int类型上调用
5.receiver()
并根据文档在这里
可以使用其invoke(...)运算符调用函数类型的值:
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 }
Run Code Online (Sandbox Code Playgroud)
正如您所见,apply是T的扩展函数,block将是接收器类型T的函数,
由于T.() T将作为lambda中的第一个参数.
现在这里的块由函数体内的block()调用,但你也可以写this.block()或block(this)
在调用此lambda之后,我们将返回T的实例(调用apply的相同实例)
因此,我们在apply中所做的是在参数中使用lambda,在调用它的同一个实例T上执行它,并返回相同的T实例
例
调用此函数将如下所示:
(StringBuilder("Hello ").apply({ append("Kotliner") }))
Run Code Online (Sandbox Code Playgroud)
但是在kotlin中,如果lambda是最后一个参数,那么funName({})你可以简单地写,而不是写作funName{}.
所以上面的代码也可以写成
StringBuilder("Hello ").apply {
append("Kotliner")
append("! ")
}
Run Code Online (Sandbox Code Playgroud)
看起来更清晰简洁.所以这样Kotlin提供了像Groovy这样的DSL结构.
这是关于同一主题的非常好的博客
| 归档时间: |
|
| 查看次数: |
4560 次 |
| 最近记录: |