- 原文地址:
- 原文作者:
- 译文出自:
- 本文永久链接:
- 译者:
在奥地利旅行期间,我参观了维也纳的奥地利国家图书馆。特别是国会大厅,这个令人惊叹的空间感觉就像印第安纳琼斯电影中的一些东西。房间周围的空间是这些门被装在架子上,很容易想象它们背后隐藏着什么样的秘密。
然而,事实证明,它们只是简单的图书馆。
让我们假设我们有一个应用程序来跟踪库中的书籍。有一天,我们想知道这个系列中最长和最短的书是什么。之后,我们编写代码,允许我们找到这两个:
val shortestBook = library.minBy { it.pageCount }val longestBook = library.maxBy { it.pageCount }复制代码
完美!但这让我感到疑惑,这些方法是如何工作的?it
是怎么知道的,只是写了 it.pageCount
,到底该怎么做呢?
我做的第一件事就是定义 minBy
和 maxBy
,这两者都是在 。由于它们几乎完全相同,所以让我们来看看 maxBy
,它从 1559 行开始。
那里的方法是在 [Iterable](https://developer.android.com/reference/java/lang/Iterable)
接口上构建的,但是如果我们做一个小的重写来使用[Collection](https://developer.android.com/reference/java/util/Collection)
s,也许将一些变量的重命名变的更冗长,更容易理解:
public inline fun> Collection .maxBy(selector: (T) -> R): T? { if (isEmpty()) return null var maxElement = first() var maxValue = selector(maxElement) for (element in this) { val value = selector(element) if (maxValue < value) { maxElement = element maxValue = value } } return maxElement}复制代码
我们可以看到它只是在 Collection
中获取每个元素,检查来自 selector
的值是否大于它看到的最大值。如果是,则保存元素和值。最后,它返回它找到的最大元素。相当简单。
然而 selector
,看起来很整洁,它必须是允许我们在上面使用 it.pageCount
的东西,所以让我们再看看它。
即使只是在这一行中,甚至还有相当多的语法糖。在这种情况下,对于 selector: (T) -> R
来说是一个带有单个参数 T
的函数,并返回一些类型 R
相关的返回值。
可行的方法是 Kotlin 包含一组名为 FunctionN
的接口,其中 N
是它接受的参数数量。由于我们有一个参数,我们可以实现 Function1
接口,然后在我们的代码中使用它:
class BookSelector : Function1{ override fun invoke(book: Book): Int { return book.pageCount }} val longestBook = library.maxBy(BookSelector())复制代码
这无疑显示了它的工作原理。selector
是一个 Function1
,当给定 Book
时,返回一个 Int
。然后,maxBy
获取 Int
并将其与它具有的值进行比较。
顺便说一句,这也解释了为什么泛型参数 R
具有类型 R [implements] Comparable <R>
。如果 R
不是 Comparable
,我们不能做 if(maxValue <value)
。
接下来的问题是,我们如何从那开始,到我们开始的一个循环?让我们逐步完成整个过程。
首先,代码可以替换为 lambda
,它已经减少了很多:
val longestBook = library.maxBy({ it.pageCount})复制代码
下一步是如果方法的最后一个参数是 lambda,我们可以关闭括号,然后将 lambda 添加到行的末尾,如下所示:
val longestBook = library.maxBy() { it.pageCount}复制代码
最后,如果一个方法只接受一个 lambda 参数,我们就可以完全放弃 ()
方法,这会让我们回到初始代码:
val longestBook = library.maxBy { it.pageCount }复制代码
但是等等!那个 Function1
要怎么样!我每次使用它时都会执行分配吗?
这是一个很好的问题!好消息是,不,你不是。如果你再看一遍,你会看到它 maxBy
被标记为一个 inline
函数。这在编译期时会在源级别发生,因此虽然编译的代码比最初看起来的样本多,但是没有任何显着的性能影响,当然也没有对象分配。
真棒!现在,我们不仅知道图书馆中最短(也是最长)的书籍,我们还能更好地理解 maxBy
它是如何工作的。我们看到 Kotlin 如何使用[FunctionN](#full)
lambda 的接口,以及如何将 lambda 表达式移到函数的参数列表之外。最后,我们知道,当只有一个 lambda 参数调用函数时,可以通常使用。
查看 博客,了解更多精彩内容,敬请期待更多关于 Kotlin 的文章!
如果发现译文存在错误或其他需要改进的地方,欢迎到 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。
是一个翻译优质互联网技术文章的社区,文章来源为 上的英文分享文章。内容覆盖 、、、、、、、等领域,想要查看更多优质译文请持续关注 、、。