[譯]記一次Kotlin官方文檔翻譯的PR(內(nèi)聯(lián)類)

簡(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,一般人不告訴他

qrcode_for_gh_109398d5e616_430.jpg

歡迎關(guān)注Kotlin開發(fā)者聯(lián)盟厦滤,這里有最新Kotlin技術(shù)文章,每周會(huì)不定期翻譯一篇Kotlin國(guó)外技術(shù)文章歼狼。如果你也喜歡Kotlin掏导,歡迎加入我們~~~

Kotlin系列文章,歡迎查看:

Effective Kotlin翻譯系列

原創(chuàng)系列:

翻譯系列:

實(shí)戰(zhàn)系列:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市坯汤,隨后出現(xiàn)的幾起案子虐唠,更是在濱河造成了極大的恐慌,老刑警劉巖惰聂,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疆偿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡搓幌,警方通過查閱死者的電腦和手機(jī)翁脆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鼻种,“玉大人反番,你說我怎么就攤上這事〔嬖浚” “怎么了罢缸?”我有些...
    開封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)投队。 經(jīng)常有香客問我枫疆,道長(zhǎng),這世上最難降的妖魔是什么敷鸦? 我笑而不...
    開封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任息楔,我火速辦了婚禮,結(jié)果婚禮上扒披,老公的妹妹穿的比我還像新娘值依。我一直安慰自己,他們只是感情好碟案,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開白布愿险。 她就那樣靜靜地躺著,像睡著了一般价说。 火紅的嫁衣襯著肌膚如雪辆亏。 梳的紋絲不亂的頭發(fā)上风秤,一...
    開封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音扮叨,去河邊找鬼缤弦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛彻磁,可吹牛的內(nèi)容都是我干的碍沐。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼兵迅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼抢韭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起恍箭,我...
    開封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤刻恭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后扯夭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鳍贾,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年交洗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了骑科。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡构拳,死狀恐怖咆爽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情置森,我是刑警寧澤斗埂,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站凫海,受9級(jí)特大地震影響呛凶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜行贪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一漾稀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧建瘫,春花似錦崭捍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拣播,卻和暖如春晾咪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贮配。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工谍倦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泪勒。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓昼蛀,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親圆存。 傳聞我的和親對(duì)象是個(gè)殘疾皇子叼旋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容