こんにちは、DHLです。公開アカウント: 興味深いハードコアなオリジナル コンテンツの共有に焦点を当てた ByteCode、Kotlin、Jetpack、パフォーマンスの最適化、システム ソース コード、アルゴリズムとデータ構造、アニメーション、大規模な工場での経験
全文は動画版とテキスト版に分かれています。
- テキストバージョン: テキストは詳細と深さに焦点を当てています, いくつかの知識ポイント, ビデオは表現するのが簡単ではありません, テキストの説明はより正確です
- 動画版:アニメーション形式で動画がより直感的になります テキスト版を読んだ後、動画を見ながら知識ポイントがより明確になりますTwitterの興味深いコード
これは海外のKotlin GDEのボスがTwitterでシェアしたコードです. とても面白いと思います. コードは以下のようなものです. 出力結果を10秒かけて考えてみましょう.
fun printE() = { println("E") }
fun main() {
if (true) println("A")
if (true) { println("B") }
if (true) {
{ println("C") }
}
{ println("D") }
printE()
when {
true -> { println("F") }
}
}
复制代码
Twitterのコメント欄にも、さまざまな回答が寄せられています。
実際、最終的な出力は次のようになります。
A
B
F
复制代码
乱雑な中括弧がたくさんあるのを初めて見たときの気持ちはわかりませんが、このコードを最初に見たとき、とても面白いと思いました。
実際のプロジェクトで、このように中括弧を入れ子にしている小さなパートナーがいれば、間違いなく引き抜かれて日光にさらされると思います。しかし、このコードを注意深く観察すると、Kotlin 関連の多くの知識ポイントを学ぶことができます。なぜ最終的な出力がA B F
.
下図の赤くマークされた部分、if
式、when ... case
式、式にコードが1行しかない場合、中括弧は省略でき、プログラムはコード位置まで実行されたときに対応する結果を出力します。A B F
.
那为什么 C D E
没有打印,因为图中绿色部分是 lambda
表达式,在 Kotlin 中 lambda
表达式非常的自由,它可以出现在很多地方比如方法内、 if
表达式内、循环语句内、甚至赋值给一个变量、或者当做方法参数进行传递等等。
lambda
表达式用花括号包裹起来,用箭头把实参列表和 lambda
函数体分离开来,如下所示。
{ x: Int -> println("lambda 函数体") }
复制代码
如果没有参数,上面的代码可以简写成下面这样。
{ println("lambda 函数体") }
复制代码
而 C D E
的输出语句在 lambda
函数体内, lambda
表达式我们可以理解为高阶函数,在上面的代码中只是声明了这个函数,但是并没有调用它,因此不会执行,自然也就不会有任何输出。现在我将上面的代码做一点点修改,在花 10s 思考一下输出结果是什么。
fun printE() = { println("E") }
fun main() {
if (true) println("A")
if (true) { println("B") }
if (true) {
{ println("C") }()
}
{ println("D") }()
printE()()
when {
true -> { println("F") }
}
}
复制代码
最后的输出结果是:
A
B
C
D
E
F
复制代码
应该有小伙伴发现了我做了那些修改,我只是在 lambda
表达式后面加了一个 ()
,表示执行当前的 lambda
表达式,所以我们能看到对应的输出结果。如下图所示,
lambda
表达式最终会编译成 FunctionN
函数,如下图所示。
如果没有参数会编译成 Function0
,一个参数编译成 Function1
,以此类推。FunctionN
重载了操作符 invoke
。如下图所示。
因此我们可以调用 invoke
方法来执行 lambda
表达式。
{ println("lambda 函数体") }.invoke()
复制代码
当然 Kotlin 也提供了更加简洁的方式,我们可以使用 ()
来代替 invoke()
,最后的代码如下所示。
{ println("lambda 函数体") }()
复制代码
到这里我相信小伙伴已经明白了上面代码输出的结果,但是这里隐藏了一个有性能损耗的风险点,分享一段我在实际项目中见到的代码,示例中的代码,我做了简化。
fun main() {
val count = 2
(1..10).forEach { value ->
calculate(value) { result ->
val average = result / count
println(average)
}
}
}
fun calculate(x: Int, lambda: (result: Int) -> Unit) {
lambda(x + 10)
}
复制代码
上面的代码其实存在一个比较严重的性能问题,我们看一下反编译后的代码。
每次在循环中都会创建一个 FunctionN
的对象,那么如何避免这个问题,我们可以将 lambda
表达式放在循环之外,这样就能保证只会创建一个 FunctionN
对象,我们来看一下修改后的代码。
fun calculate(x: Int, lambda: (result: Int) -> Unit) {
lambda(x + 10)
}
fun main() {
val count = 2
val lambda: (result: Int) -> Unit = { result ->
val average = result / count
println(average)
}
(1..10).forEach { value ->
calculate(value, lambda)
}
}
复制代码
全文到这里就结束了,感谢你的阅读,坚持原创不易,欢迎在看、点赞、分享给身边的小伙伴,我会持续分享原创干货!!!
真诚推荐你关注我,公众号:ByteCode ,持续分享硬核原创内容,Kotlin、Jetpack、性能优化、系统源码、算法及数据结构、动画、大厂面经。
近期必读热门文章
- 谁动了我的内存,揭秘 OOM 崩溃下降 90% 的秘密
- 反射技巧让你的性能提升 N 倍
- 90%人不懂的泛型局限性,泛型擦除,星投影
- 90%的人都不知道的知识点,Kotlin 和 Java 的协变和逆变
- CPU 如何记录函数调用过程和返回过程
- 揭秘反射真的很耗时吗,射 10 万次耗时多久
- 揭秘 Kotlin 1.6.20 重磅功能 Context Receivers
- Stack Overflow 上最热门的 10 个 Kotlin 问题
- Android 12 已来,你的 App 崩溃了吗?
- Google 宣布废弃 LiveData.observe 方法
- 影响性能的 Kotlin 代码(一)
- 揭秘 Kotlin 中的 == 和 ===
最后推荐长期更新和维护的项目
-
个人博客,将所有文章进行分类,欢迎前去查看 hi-dhl.com
-
KtKit 小巧而实用,用 Kotlin 语言编写的工具库,欢迎前去查看 KtKit
-
AndroidX Jetpack に関連する最も完全で最新のコンポーネントと、関連コンポーネントの原理分析に関する記事の実用的なプロジェクトを確立する予定です. Jetpack の新しいメンバーを徐々に追加しており、ウェアハウスは継続的に更新されています. AndroidX-Jetpackを確認することを歓迎します-練習
-
LeetCode / 剣術提供 / 国内外メーカーのインタビュー質問 / マルチスレッドの問題解決、言語 Java と kotlin、さまざまな解決策、問題解決のアイデア、時間の複雑さ、空間の複雑さの分析を含む
- 剣は、国内外のメーカーのオファーとインタビューの質問を指します:オンライン読書
- LeetCode 一連の質問:オンライン リーディング