Lambda 如何设计高阶函数
高阶函数的参数为Lambda 如何设计高阶函数,lambda,kotlin,functional-programming,Lambda,Kotlin,Functional Programming,高阶函数的参数为 函数类型或 带有接收器的函数类型 我们习惯于使用kotlin标准数据库中的过滤和: @Test fun `filter example`() { val filtered = listOf("foo", "bar").filter { it.startsWith("f") } assertThat(filtered).containsOnly("foo") } @Test fun `with example`() { va
- 函数类型或
- 带有接收器的函数类型
@Test
fun `filter example`() {
val filtered = listOf("foo", "bar").filter {
it.startsWith("f")
}
assertThat(filtered).containsOnly("foo")
}
@Test
fun `with example`() {
val actual = with(StringBuilder()) {
append("foo")
append("bar")
toString()
}
assertThat(actual).isEqualTo("foobar")
}
filter
使用函数类型参数,with
使用函数类型参数与receiver。因此,lambdas被传递到filter
使用it
访问iterable的元素,而lambdas被传递到使用this
访问StringBuilder
我的问题是:当我声明自己的高阶函数时,是否有一个经验法则,使用哪种风格(它与此相对)
换言之:
为什么过滤不是这样设计的
inline fun <T> Iterable<T>.filter2(predicate: T.() -> Boolean): List<T> = filter { it.predicate() }
你只是不想总是和接受者一起工作。例如,考虑你的<代码>过滤器<代码>直接在元素上工作,你必须使用<代码>这个限定符,然后在比较中:
val filtered = listOf("foo", "bar").filter2 {
this == "f"
}
这看起来既奇怪又不自然。这个
指向什么?
您将此
的范围更改为指向接收器,如果您想访问“外部”此
,它将如下所示:
this@SomeClass.c =="f"
另一个缺点是,您无法命名参数。例如,考虑嵌套的lambda。无论是它
还是这个
都不合适。您必须提供自定义名称
如果你真的想切换到接收方的范围,你应该考虑一下。有些情况是完美的用例,尤其是。对于通常的高阶函数,您根本不希望具有此功能
我认为很难为此制定一个“规则”,但作为初学者,您可以阅读JetBrains关于如何在可用范围函数之间进行选择的内容(让
,运行
,也
,应用
,使用
):
您是在块中的多个对象上调用方法,还是将上下文对象的实例作为参数传递?如果是,请使用其中一个函数,该函数允许您访问上下文对象,而不是使用this(也可以使用或let)。如果在块中根本没有使用接收器,也可以使用
我的经验法则如下: 只要有可能需要命名lambda参数,我就使用
(Type)->Unit
如果我确信我不会给它命名(因此从上下文中可以清楚地看出,我操作的所有东西都是这个
),或者我甚至想禁止命名(生成器?),那么我就使用类型。->Unit
使用
,应用
和运行
都使用第二种方法。。。对我来说,这是有道理的:
with(someString) {
toUpperCase() // operates on someString... already sounds like: "with some string (do) to upper case"
}
someString.run(::println) // run println with someString; actually: someString.run { println(this) } // e.g.: print this [some string]
// actually I find this a bad sample... I usually use run where the thing to be run is from the receiver...
SomeComplexObject().apply {
// apply being similar to a builder
complex1 = 3
complex2 = 4
}.run {
// fully constructed complex object
complexOperationWithoutReturnValue() // this method is part of SomeComplexObject
} // discarding everything here...
以下是我使用第二种方法的示例:
fun sendMail(from : String, to : String, msgBuilder : MessageBuilder.() -> Unit)
sendMail("from", "to") {
subject("subject")
body("body")
}
使用
it
或一个参数(例如builder->
),它只会变得更丑陋,并且不会真正为上下文添加内容 第一个是lamabda,第二个是带接收器的lambda。
fun sendMail(from : String, to : String, msgBuilder : MessageBuilder.() -> Unit)
sendMail("from", "to") {
subject("subject")
body("body")
}