Kotlin 作用域函數 let 的實現原理

Kotlin 中的 let 是一個 標準庫擴展函數,它廣泛用于作用域函數(Scope Functions)中,尤其適用于對可空對象(nullable)做非空判斷并執行代碼塊的場景。

示例代碼

val name: String? = "123"
name?.let {println(it)
}

這個例子等價于:

if (name != null) {val it = nameprintln(it)
}

也就是說,name?.let { ... } 只有當 name 非空時才執行 let 的 lambda 塊。lambda 表達式中 it 就是 name 的非空值。let 返回 lambda 的返回值。

實現原理

Kotlin 的 let 函數定義在 commonMain/kotlin/util/Standard.kt 中,源碼如下:

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}return block(this)
}

它是一個 內聯(inline)函數,在編譯時會被內聯展開,避免 lambda 帶來的性能開銷。泛型 <T, R> 表示接收一個類型為 T 的對象,返回一個類型為 R 的結果。T.let 表示 let 是類型 T 的擴展函數。block: (T) -> R 是接收 T 的函數(lambda 表達式)。也就是說,它只是將當前對象 this 傳入了 block(this) 中。

@kotlin.internal.InlineOnly,這是一個 注解(Annotation),用于標記某個函數 只能在被 inline(內聯)時使用,否則編譯器會報錯。

比如下面的代碼:

@InlineOnly
inline fun <T> T.let(block: (T) -> Unit): Unit {block(this)
}

表示這個 let 函數 不會生成實際函數調用(它只能內聯展開),避免 Java 或非 Kotlin 編譯器調用這個方法。

為什么要限制只能 inline?為了提高性能,避免生成函數對象和調用開銷,同時 確保代碼安全地被內聯使用,防止其他模塊通過反射或 Java 調用這個方法。

contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}

這是Kotlin 的 Contract DSL,用于 給編譯器更多關于 lambda 執行行為的信息,提升智能分析、空安全和優化。表示block 這個 lambda 參數,在函數調用過程中會 被調用且只調用一次(Exactly once)。這使得編譯器可以進行一些靜態分析優化,例如在下面這種空檢查中,判斷 name 非空:

val name: String? = "abc"
name?.let {// 編譯器知道這里 it 一定非空,不會再要求你加 !!println(it.length) // 安全
}

InvocationKind 類型說明:

  • EXACTLY_ONCE:block 會被調用且僅一次
  • AT_LEAST_ONCE:一定會調用一次或多次
  • AT_MOST_ONCE:最多一次,可能不調用
  • UNKNOWN:不確定

編譯器依靠這個信息進行控制流分析,提升非空智能推斷、性能優化、檢測死代碼等能力。

R 是泛型返回類型。

inline fun <T, R> T.let(block: (T) -> R): R {return block(this)
}

<T, R> 是泛型聲明,T是調用 let 的對象類型(接收者),Rblock 函數返回值的類型,也是 let 函數的最終返回值類型。

舉例:

val name = "abc"
val length: Int = name.let { it.length } // block 返回 Int,所以 R = Int

也可以是任意類型:

val upper = "abc".let { it.uppercase() } // R = String
val printResult = "abc".let { println(it) } // R = Unit

編譯后字節碼

比如:

val name: String? = "123"
name?.let {println(it)
}

大致翻譯成 Java 是:

String name = "123";
if (name != null) {System.out.println(name);
}

編譯器把 ?.let { ... } 直接轉成了 if != null 的判斷。lambda 是內聯展開的,不會有額外函數對象生成,所以效率非常高。

常見用途

處理 nullable 類型

val name: String? = getName()
name?.let {println("非空值是:$it")
}

鏈式調用

val result = listOf(1, 2, 3).map { it * 2 }.let {it.joinToString()
}

限定作用域變量(避免變量污染):

val userInput = readLine()
userInput?.let {val trimmed = it.trim()println("你輸入的是:$trimmed")
}
// trimmed 在此作用域外不可見

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90138.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90138.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90138.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從FDTD仿真到光學神經網絡:機器學習在光子器件設計中的前沿應用工坊

FDTD仿真與光學神經網絡的基礎概念 FDTD&#xff08;時域有限差分&#xff09;是一種數值方法&#xff0c;用于求解麥克斯韋方程組&#xff0c;廣泛應用于光子器件設計。光學神經網絡通過光波導、衍射元件等物理結構實現矩陣運算&#xff0c;具有低能耗、高并行的優勢。 機器學…

在Ubutu22系統上面離線安裝Go語言環境【教程】

0.引言 Go語言&#xff08;又稱Golang&#xff09;是Google開發的一種靜態強類型、編譯型、并發型編程語言&#xff0c;由Robert Griesemer、Rob Pike和Ken Thompson于2007年開始設計&#xff0c;2009年正式發布。 1.到官網下載壓縮包 2.從win10系統離線上傳壓縮包給ubuntu22…

CMake實踐:CMake3.30版本之前和之后鏈接boost的方式差異

目錄 1.背景 2.boost引入CMake時機 3.CMake 3.30 之前&#xff08;含 3.29&#xff09;鏈接 Boost 的方式 4.CMake 3.30 及之后鏈接 Boost 的方式 5.CMake3.30后引入Boost的步驟 6.遷移建議&#xff08;3.30 之前 → 3.30 之后&#xff09; 7.CMake 3.30 移除FindBoost的…

告別掛馬風險!PBootCMS完美替代方案BadouCMS

開發企業網站時一直比較喜歡用pbootcms,標簽套用很簡單&#xff0c;使用也方便。 但是pbootcms一直有被掛馬的問題&#xff0c;官方好像也不怎么更新了&#xff01;換過好幾個cms&#xff0c;比如eyoucms、dedecms、帝國等等&#xff0c;感覺都不怎么能用得習慣&#xff0c;還…

開發者如何集成AI繪畫?智創聚合API簡化Midjourney接入

在 AI 繪畫領域&#xff0c;Midjourney 的大名如雷貫耳&#xff0c;其強大的圖像生成能力&#xff0c;能將我們腦海中的奇思妙想&#xff0c;迅速轉化為精美的視覺畫面&#xff0c;深受設計師、藝術家以及廣大創意愛好者的青睞。然而&#xff0c;使用 Midjourney 的過程中&…

pycharm回車、刪除、方向鍵和快捷鍵等不能使用原因

解決方法 &#xff1a;菜單欄中的Tools取消勾選Vim Emulator 原因 &#xff1a;新版的pycharm安裝中&#xff0c;默認安裝了vim擴展&#xff0c;一旦安裝了pycharm在編寫代碼時會默認使用Vim編輯器

修復ffmpeg.dll丟失錯誤|6種解決ffmpeg.dll方法詳細教程

看到電腦提示“ffmpeg.dll丟失”&#xff0c;很多人會懵。ffmpeg.dll 是個處理視頻、音頻的關鍵文件。它要是沒了或壞了&#xff0c;軟件就打不開或直接閃退。常見原因是軟件安裝不全、文件被刪、或者中病毒。下面說說它是干嘛的&#xff0c;再給解決辦法。一.ffmpeg.dll 到底是…

OkHttp 與 Stetho 結合使用:打造強大的 Android 網絡調試工具鏈

前言在 Android 應用開發過程中&#xff0c;網絡請求的調試一直是一個重要但具有挑戰性的環節。Facebook 開發的 Stetho 是一個強大的調試工具&#xff0c;當它與 OkHttp 結合使用時&#xff0c;可以為我們提供前所未有的網絡請求洞察能力。本文將詳細介紹如何將這兩者結合使用…

LangGraph教程10:LangGraph ReAct應用

文章目錄 ReAct 預構建的代理 向 ReAct 代理添加記憶 向 ReAct 代理添加系統提示 向 ReAct 代理添加人機交互 ReAct 官方文檔地址:https://langchain-ai.github.io/langgraph/how-tos/#prebuilt-react-agent 中文文檔地址:https://www.aidoczh.com/langgraph/how-tos/#react…

安卓第一個項目

測試所有攝像頭 安卓CameraX&#xff1a;https://developer.android.com/media/grow/spatial-audio?hlzh-cn 1、MainActivity.java // 定義包名 package com.mms.densenapplication;// 引入 AppCompatActivity&#xff0c;支持兼容性更強的 Activity import androidx.appcompa…

Google Gemini 體驗

文章中代碼倉庫 gemini 谷歌推出的 AI 只能模型 Gemini官網Gemini ChatGemini開發者文檔Gemini SDK 所有模型 模型變體輸入輸出優化目標Gemini 2.5 Pro gemini-2.5-pro音頻、圖片、視頻、文本和 PDF文本增強的思考和推理能力、多模態理解能力、高級編碼能力等Gemini 2.5 Fla…

Trae安裝指定版本的插件

前情 Trae是屬于國產的跟 Cursor類似的AI編程IDE&#xff0c;我也是第一時間體驗Trae的&#xff0c;雖然相比Cursor弱了一些&#xff0c;但是也絕對勝任了&#xff0c;前端因為排隊問題我轉戰了Cursor&#xff0c;等到Trae出收費模式前&#xff0c;我已經辦了Cursor會員了&…

【技術追蹤】用于醫學圖像合成和分割的噪聲一致孿生擴散模型(CVPR-2025)

孿生擴散模型&#xff0c;生成息肉圖像用于提升分割性能&#xff01; 論文&#xff1a;Noise-Consistent Siamese-Diffusion for Medical Image Synthesis and Segmentation 代碼&#xff1a;https://github.com/Qiukunpeng/Siamese-Diffusion 0、摘要 深度學習已徹底革新醫學影…

Crontab詳解

crontab是Unix/Linux系統中用于設置周期性任務的工具&#xff0c;通過編輯配置文件實現定時執行命令或腳本。以下是其語法規則和核心要點&#xff1a; 一、基本格式 * * * * * command - - - - - | | | | | | | | | ----…

中國1km逐月潛在蒸散發數據集 - matlab按shp批量裁剪

中國1km逐月潛在蒸散發數據集 - matlab按shp批量裁剪 1. 數據概述 2 利用掩膜文件對數據進行裁剪 3 完整代碼 4 結語 本篇繼續處理氣象數據,中國1km逐月潛在蒸散發數據集同前節介紹的中國1km降水數據集一樣,都可以從國家青藏高原科學數據中心獲得,數據具有同樣的空間分辨率(…

Node.js鏈接MySql

前言&#xff1a; 在現代 Web 開發和后端服務中&#xff0c;Node.js 因其高性能和異步特性被廣泛使用。MySQL 作為流行的關系型數據庫之一&#xff0c;提供了穩定高效的數據存儲和管理能力。將 Node.js 與 MySQL 結合&#xff0c;可以構建強大的數據驅動型應用。 一、環境準備…

Charles 的 Windows proxy 對爬取瑞數6 網站接口數據的作用分析

其實本文還是源于上個月的這篇文章 ??▼ 耗時兩天半&#xff0c;利用 DrissionPage繞過瑞數6&#xff0c;爬取某藥*局數據經歷~ 不同點是&#xff0c;當時爬取的是列表頁&#xff08;已爬完&#xff09;&#xff0c;后面爬取的是詳情頁&#xff01;懂的都懂&#xff0c;差別還…

PHP 測驗

PHP 測驗 引言 PHP 作為一種流行的開源服務器端腳本語言,被廣泛應用于網頁開發、服務器端編程等領域。為了幫助大家更好地理解和掌握 PHP,我們特此推出本 PHP 測驗。通過以下問題,您可以檢驗自己的 PHP 知識水平,同時也能了解自己在哪些方面需要加強。 測驗內容 問題一…

階段1--Linux中的文件服務器(FTP、NAS、SSH)

目錄 一、FTP Server 1.1.簡介 1.2.FTP基礎 1.2.1.控制端口 1.2.2.數據端口 1.3.FTP Server默認配置 1.3.1.安裝vsftp 1.3.2.準備分發的文件 1.3.3.啟動服務 1.3.4.關閉防火墻 1.4.FTP Client&#xff08;默認僅能下載文件&#xff09; 1.4.1.LinuxFTP客戶端程序1&#xff1a;l…

SpringBoot與Vue實戰:高效開發秘籍

Spring Boot 是什么? Spring Boot 簡介 Spring Boot 是基于 Spring 框架的快速開發工具,旨在簡化 Spring 應用的初始搭建和開發過程。它通過約定大于配置的原則,提供自動配置、內嵌服務器和依賴管理等功能,使開發者能夠快速構建獨立運行的、生產級別的應用。 核心特點 …