簡(jiǎn)述: 這幾天突然沒更新文章了尤筐,可能有的小伙伴認(rèn)為寒冬將至,是不是認(rèn)為我跑路了(哈哈日熬,確實(shí)不是哈棍厌,這幾天感冒挺厲害的,再加上前幾天連續(xù)熬夜寫文章竖席,感覺快扛不住了耘纱,所以暫時(shí)休息停更了一周。這不這篇內(nèi)聯(lián)類官網(wǎng)文檔的翻譯毕荐,已經(jīng)拖了很多天束析,今天總算給中文社區(qū)的大佬提了PR)。
翻譯說明:
原標(biāo)題: inline-class
原文地址: Kotlin官網(wǎng)
譯文地址: Kotlin中文站-內(nèi)聯(lián)類
內(nèi)聯(lián)類
內(nèi)聯(lián)類僅在 Kotlin 1.3 之后版本可用憎亚,目前還是實(shí)驗(yàn)性的员寇。關(guān)于詳情請(qǐng)參見下文
有時(shí)候,業(yè)務(wù)邏輯需要圍繞某種類型創(chuàng)建包裝器第美。然而蝶锋,由于額外的堆內(nèi)存分配問題,它會(huì)引入運(yùn)行時(shí)的性能開銷什往。此外扳缕,如果被包裝的類型是原生類型,性能的損失是很糟糕的恶守,因?yàn)樵愋屯ǔT谶\(yùn)行時(shí)就進(jìn)行了大量?jī)?yōu)化第献,然而他們的包裝器卻沒有得到任何特殊的處理贡必。
為了解決這類問題兔港,Kotlin引入了一種被稱為 內(nèi)聯(lián)類
的特殊類,它通過在類的前面定義一個(gè) inline
修飾符來聲明:
<div class="sample" markdown="1" theme="idea" data-highlight-only>
inline class Password(val value: String)
</div>
內(nèi)聯(lián)類必須含有唯一的一個(gè)屬性在主構(gòu)造函數(shù)中初始化仔拟。在運(yùn)行時(shí)衫樊,將使用這個(gè)唯一屬性來表示內(nèi)聯(lián)類的實(shí)例 (關(guān)于運(yùn)行時(shí)的內(nèi)部表達(dá)請(qǐng)參閱 下文):
<div class="sample" markdown="1" theme="idea" data-highlight-only>
// 不存在 'Password' 類的真實(shí)實(shí)例對(duì)象
// 在運(yùn)行時(shí),'securePassword' 僅僅包含 'String'
val securePassword = Password("Don't try this in production")
</div>
這就是內(nèi)聯(lián)類的主要特性利花,它靈感來源于 “inline” 這個(gè)名稱:類的數(shù)據(jù)被 “內(nèi)聯(lián)”到該類使用的地方(類似于 內(nèi)聯(lián)函數(shù) 中的代碼被內(nèi)聯(lián)到該函數(shù)調(diào)用的地方)科侈。
成員
內(nèi)聯(lián)類支持普通類中的一些功能。特別是炒事,內(nèi)聯(lián)類可以聲明屬性與函數(shù):
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
inline class Name(val s: String) {
val length: Int
get() = s.length
fun greet() {
println("Hello, $s")
}
}
fun main() {
val name = Name("Kotlin")
name.greet() // `greet` 方法會(huì)作為一個(gè)靜態(tài)方法被調(diào)用
println(name.length) // 屬性的 get 方法會(huì)作為一個(gè)靜態(tài)方法被調(diào)用
}
</div>
然而臀栈,內(nèi)聯(lián)類的成員也有一些限制:
- 內(nèi)聯(lián)類不能含有 init 代碼塊
- 內(nèi)聯(lián)類不能含有 inner 類
- 內(nèi)聯(lián)類不能含有幕后字段
- 因此,內(nèi)聯(lián)類只能含有簡(jiǎn)單的計(jì)算屬性(不能含有延遲初始化/委托屬性)
繼承
內(nèi)聯(lián)類允許去繼承接口
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
interface Printable {
fun prettyPrint(): String
}
inline class Name(val s: String) : Printable {
override fun prettyPrint(): String = "Let's $s!"
}
fun main() {
val name = Name("Kotlin")
println(name.prettyPrint()) // 仍然會(huì)作為一個(gè)靜態(tài)方法被調(diào)用
}
</div>
禁止內(nèi)聯(lián)類參與到類的繼承關(guān)系結(jié)構(gòu)中挠乳。這就意味著內(nèi)聯(lián)類不能繼承其他的類而且必須是 final权薯。
表示方式
在生成的代碼中姑躲,Kotlin編譯器為每個(gè)內(nèi)聯(lián)類保留一個(gè)包裝器。內(nèi)聯(lián)類的實(shí)例可以在運(yùn)行時(shí)表示為包裝器或者基礎(chǔ)類型盟蚣。這就類似于 Int
可以表示為原生類型 int
或者包裝器 Integer
黍析。
為了生成性能最優(yōu)的代碼,Kotlin 編譯更傾向于使用基礎(chǔ)類型而不是包裝器屎开。 然而阐枣,有時(shí)候使用包裝器是必要的。一般來說奄抽,只要將內(nèi)聯(lián)類用作另一種類型蔼两,它們就會(huì)被裝箱。
<div class="sample" markdown="1" theme="idea" data-highlight-only>
interface I
inline class Foo(val i: Int) : I
fun asInline(f: Foo) {}
fun <T> asGeneric(x: T) {}
fun asInterface(i: I) {}
fun asNullable(i: Foo?) {}
fun <T> id(x: T): T = x
fun main() {
val f = Foo(42)
asInline(f) // 拆箱操作: 用作 Foo 本身
asGeneric(f) // 裝箱操作: 用作泛型類型 T
asInterface(f) // 裝箱操作: 用作類型 I
asNullable(f) // 裝箱操作: 用作不同于 Foo 的可空類型 Foo?
// 在下面這里例子中逞度,'f' 首先會(huì)被裝箱(當(dāng)它作為參數(shù)傳遞給 'id' 函數(shù)時(shí))然后又被拆箱(當(dāng)它從'id'函數(shù)中被返回時(shí))
// 最后宪哩, 'c' 中就包含了被拆箱后的內(nèi)部表達(dá)(也就是 '42'), 和 'f' 一樣
val c = id(f)
}
</div>
因?yàn)閮?nèi)聯(lián)類既可以表示為基礎(chǔ)類型有可以表示為包裝器第晰,引用相等對(duì)于內(nèi)聯(lián)類而言毫無意義锁孟,因此這也是被禁止的。
名字修飾
由于內(nèi)聯(lián)類被編譯為其基礎(chǔ)類型茁瘦,因此可能會(huì)導(dǎo)致各種模糊的錯(cuò)誤品抽,例如意想不到的平臺(tái)簽名沖突:
<div class="sample" markdown="1" theme="idea" data-highlight-only>
inline class UInt(val x: Int)
// 在JVM平臺(tái)上被表示為'public final void compute(int x)'
fun compute(x: Int) { }
// 同理,在JVM平臺(tái)上也被表示為'public final void compute(int x)'!
fun compute(x: UInt) { }
</div>
為了緩解這種問題甜熔,一般會(huì)通過在函數(shù)名后面拼接一些穩(wěn)定的哈希碼來重命名函數(shù)圆恤。 因此, fun compute(x: UInt)
將會(huì)被表示為 public final void compute-<hashcode>(int x)
, 以此來解決沖突的問題。
請(qǐng)注意在Java中
-
是一個(gè) 無效的 符號(hào)腔稀,也就是說在Java中不能調(diào)用使用內(nèi)聯(lián)類作為形參的函數(shù)盆昙。
內(nèi)聯(lián)類與類型別名
初看起來,內(nèi)聯(lián)類似乎與類型別名非常相似焊虏。實(shí)際上淡喜,兩者似乎都引入了一種新的類型,并且都在運(yùn)行時(shí)表示為基礎(chǔ)類型诵闭。
然而炼团,關(guān)鍵的區(qū)別在于類型別名與其基礎(chǔ)類型(以及具有相同基礎(chǔ)類型的其他類型別名)是 賦值兼容 的,而內(nèi)聯(lián)類卻不是這樣疏尿。
換句話說瘟芝,內(nèi)聯(lián)類引入了一個(gè)真實(shí)的新類型,與類型別名正好相反褥琐,類型別名僅僅是為現(xiàn)有的類型取了個(gè)新的替代名稱(別名):
<div class="sample" markdown="1" theme="idea" data-highlight-only>
typealias NameTypeAlias = String
inline class NameInlineClass(val s: String)
fun acceptString(s: String) {}
fun acceptNameTypeAlias(n: NameTypeAlias) {}
fun acceptNameInlineClass(p: NameInlineClass) {}
fun main() {
val nameAlias: NameTypeAlias = ""
val nameInlineClass: NameInlineClass = NameInlineClass("")
val string: String = ""
acceptString(nameAlias) // 正確: 傳遞別名類型的實(shí)參替代函數(shù)中基礎(chǔ)類型的形參
acceptString(nameInlineClass) // 錯(cuò)誤: 不能傳遞內(nèi)聯(lián)類的實(shí)參替代函數(shù)中基礎(chǔ)類型的形參
// And vice versa:
acceptNameTypeAlias("") // 正確: 傳遞基礎(chǔ)類型的實(shí)參替代函數(shù)中別名類型的形參
acceptNameInlineClass("") // 錯(cuò)誤: 不能傳遞基礎(chǔ)類型的實(shí)參替代函數(shù)中內(nèi)聯(lián)類類型的形參
}
</div>
內(nèi)聯(lián)類的實(shí)驗(yàn)性狀態(tài)
內(nèi)聯(lián)類的設(shè)計(jì)目前是實(shí)驗(yàn)性的锌俱,這就是說此特性是正在 快速變化的,并且不保證其兼容性敌呈。在 Kotlin 1.3+ 中使用內(nèi)聯(lián)類時(shí)贸宏,將會(huì)得到一個(gè)警告贩汉,來表明此特性還是實(shí)驗(yàn)性的。
要想移除警告锚赤,你必須通過對(duì) kotlinc
指定 -XXLanguage:+InlineClasses
參數(shù)來選擇使用該實(shí)驗(yàn)性的特性匹舞。
在Gradle中啟用內(nèi)聯(lián)類:
<div class="sample" markdown="1" theme="idea" mode='groovy'>
compileKotlin {
kotlinOptions.freeCompilerArgs += ["-XXLanguage:+InlineClasses"]
}
</div>
關(guān)于詳細(xì)信息,請(qǐng)參見編譯器選項(xiàng)线脚。關(guān)于多平臺(tái)項(xiàng)目的設(shè)置赐稽,請(qǐng)參見使用Gradle構(gòu)建多平臺(tái)項(xiàng)目章節(jié)。
在Maven中啟用內(nèi)聯(lián)類
<div class="sample" markdown="1" theme="idea" mode='xml'>
<configuration>
<args>
<arg>-XXLanguage:+InlineClasses</arg>
</args>
</configuration>
</div>
關(guān)于詳細(xì)信息浑侥,請(qǐng)參見指定編譯器選項(xiàng)姊舵。
進(jìn)一步討論
關(guān)于其他技術(shù)詳細(xì)信息和討論,請(qǐng)參見內(nèi)聯(lián)類的語言提議
譯者有話說
為什么要翻譯官方文檔寓落,其實(shí)只想向大家傳遞一個(gè)信息: Kotlin的官方文檔確實(shí)不錯(cuò)括丁,也許學(xué)會(huì)看官方文檔才能讓你走得更快和更遠(yuǎn)。我們都知道學(xué)習(xí)一個(gè)新的技術(shù)伶选,最好的方式就是看官方文檔史飞。 為什么說Kotlin官方文檔不錯(cuò),以此次內(nèi)聯(lián)類舉例仰税,是不是還記得之前我翻譯幾篇國(guó)外大佬有關(guān)kotlin內(nèi)聯(lián)類的文章构资,可以說把內(nèi)聯(lián)類研究得很全面了,比如內(nèi)聯(lián)類自動(dòng)裝箱和性能優(yōu)化陨簇,內(nèi)聯(lián)類與typealias類型別名的區(qū)別等等吐绵,可以看下其實(shí)這些官網(wǎng)都有提到。所以國(guó)外大佬無非也是在官網(wǎng)基礎(chǔ)上對(duì)某個(gè)問題進(jìn)行更深入挖掘和探索河绽。所以多看技術(shù)官方文檔己单,能讓你對(duì)某項(xiàng)技術(shù)了解的更加全面。
問題來了耙饰,可能很多人都厭倦看英文了纹笼,所以這次給大家安利一波Kotlin官方認(rèn)準(zhǔn)的Kotlin中文站、Kotlin中文博客榔幸、Kotlin中文社區(qū)允乐。
Kotlin中文站
Kotlin中文博客
Kotlin中文社區(qū)
非常歡迎熱愛Kotlin的小伙伴們加入到Kotlin中文社區(qū),如果你想為Kotlin中文站翻譯文檔提PR的話削咆。你可以直接在中文站翻譯github地址,找到灰藍(lán)天際大佬即可。當(dāng)然你可以直接到我的下面公眾號(hào)(Kotlin開發(fā)者聯(lián)盟)留言蠢笋,給你引薦一波拨齐,哈哈。 如果你覺得翻譯不錯(cuò)昨寞,歡迎給個(gè)star瞻惋。 私人GitHub,一般人不告訴他
歡迎關(guān)注Kotlin開發(fā)者聯(lián)盟厦滤,這里有最新Kotlin技術(shù)文章,每周會(huì)不定期翻譯一篇Kotlin國(guó)外技術(shù)文章歼狼。如果你也喜歡Kotlin掏导,歡迎加入我們~~~
Kotlin系列文章,歡迎查看:
Effective Kotlin翻譯系列
- [譯]Effective Kotlin系列之考慮使用原始類型的數(shù)組優(yōu)化性能(五)
- [譯]Effective Kotlin系列之使用Sequence來優(yōu)化集合的操作(四)
- [譯]Effective Kotlin系列之探索高階函數(shù)中inline修飾符(三)
- [譯]Effective Kotlin系列之遇到多個(gè)構(gòu)造器參數(shù)要考慮使用構(gòu)建器(二)
- [譯]Effective Kotlin系列之考慮使用靜態(tài)工廠方法替代構(gòu)造器(一)
原創(chuàng)系列:
- Jetbrains開發(fā)者日見聞(三)之Kotlin1.3新特性(inline class篇)
- JetBrains開發(fā)者日見聞(二)之Kotlin1.3的新特性(Contract契約與協(xié)程篇)
- JetBrains開發(fā)者日見聞(一)之Kotlin/Native 嘗鮮篇
- 教你如何攻克Kotlin中泛型型變的難點(diǎn)(實(shí)踐篇)
- 教你如何攻克Kotlin中泛型型變的難點(diǎn)(下篇)
- 教你如何攻克Kotlin中泛型型變的難點(diǎn)(上篇)
- Kotlin的獨(dú)門秘籍Reified實(shí)化類型參數(shù)(下篇)
- 有關(guān)Kotlin屬性代理你需要知道的一切
- 淺談Kotlin中的Sequences源碼解析
- 淺談Kotlin中集合和函數(shù)式API完全解析-上篇
- 淺談Kotlin語法篇之lambda編譯成字節(jié)碼過程完全解析
- 淺談Kotlin語法篇之Lambda表達(dá)式完全解析
- 淺談Kotlin語法篇之?dāng)U展函數(shù)
- 淺談Kotlin語法篇之頂層函數(shù)羽峰、中綴調(diào)用趟咆、解構(gòu)聲明
- 淺談Kotlin語法篇之如何讓函數(shù)更好地調(diào)用
- 淺談Kotlin語法篇之變量和常量
- 淺談Kotlin語法篇之基礎(chǔ)語法
翻譯系列:
- [譯]Kotlin中內(nèi)聯(lián)類的自動(dòng)裝箱和高性能探索(二)
- [譯]Kotlin中內(nèi)聯(lián)類(inline class)完全解析(一)
- [譯]Kotlin的獨(dú)門秘籍Reified實(shí)化類型參數(shù)(上篇)
- [譯]Kotlin泛型中何時(shí)該用類型形參約束?
- [譯] 一個(gè)簡(jiǎn)單方式教你記住Kotlin的形參和實(shí)參
- [譯]Kotlin中是應(yīng)該定義函數(shù)還是定義屬性?
- [譯]如何在你的Kotlin代碼中移除所有的!!(非空斷言)
- [譯]掌握Kotlin中的標(biāo)準(zhǔn)庫函數(shù): run、with梅屉、let值纱、also和apply
- [譯]有關(guān)Kotlin類型別名(typealias)你需要知道的一切
- [譯]Kotlin中是應(yīng)該使用序列(Sequences)還是集合(Lists)?
- [譯]Kotlin中的龜(List)兔(Sequence)賽跑
實(shí)戰(zhàn)系列: