自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

6個能讓你的Kotlin代碼庫更有意思的“魔法糖”

開發(fā) 后端
我會在本文中與你分析我最喜歡的 Kotlin 語法糖,它們是在我需要寫簡潔而魯棒 Android 應(yīng)用程序組件時發(fā)現(xiàn)的。為了讓這篇文章讀起來更輕松,我把它分成三個部分。在這第一部分中,你會看到密封類和 when() 控制流函數(shù)。愉快的開始吧!

語法糖會導(dǎo)致分號的悲劇。—— Alan J. Perlis

我們不斷地失去一些東西。其中一些東西相對來說會更重要,現(xiàn)在重新揀起來還不算太晚。Kotlin 語言為程序員的生活帶來了大量新的概念和特性,它們在日常開發(fā)中使用起來會很困難。我在生產(chǎn)環(huán)境中使用了兩年 Kotlin 之后,才感受到它帶來的快樂和滿足。這是怎么發(fā)生的?原因就在那些小小的語法糖中。

我會在本文中與你分析我最喜歡的 Kotlin 語法糖,它們是在我需要寫簡潔而魯棒 Android 應(yīng)用程序組件時發(fā)現(xiàn)的。為了讓這篇文章讀起來更輕松,我把它分成三個部分。在這第一部分中,你會看到密封類和 when() 控制流函數(shù)。愉快的開始吧!

擁抱“模式匹配”的密封類

最近我的工作中有機會使用 Swift。我不僅要審核代碼,還要將其中一些組件翻譯成 Kotlin 實現(xiàn)。我讀的代碼越多,就越感到驚訝。最對我來說,最吸引人的特性是枚舉。可惜 Kotlin 的枚舉并不太靈活,我不得不挖掘合適的替代品: 密封類 。

密封類在編程界并不是什么新鮮玩意兒。事實上,密封類是一個非常知名的語言概念。Kotlin 引入了 sealed 關(guān)鍵字,它可用于類聲明,表示對類層次結(jié)構(gòu)的限制。某個值可以是有限類型中的一個,但它不能是其它類型。簡單地說,你可以使用密封類來代替枚舉,甚至做更多事情。

來看看下面的示例代碼。

 

  1. sealed class Response  
  2. data class Success(val body: String): Response()  
  3. data class Error(val code: Int, val message: String): Response()  
  4. object Timeout: Response() 

乍一看,這些代碼除只是聲明了一些簡單的繼承關(guān)系,但步步深入,就會提示一個諒人的真相。為 Response 類添加的 sealed 關(guān)鍵字到底起到了什么作用呢?提示這個問題最好的方法是使用 IntelliJ IDEA Kotlin Bytecode 工具。

6個能讓你的Kotlin代碼庫更有意思的“魔法糖”

第一 步。查看 Kotlin 字節(jié)碼 (Kotlin Bytecode)

6個能讓你的Kotlin代碼庫更有意思的“魔法糖”

第二步。將 Kotlin 字節(jié)碼反編譯成 Java 代碼

經(jīng)過這樣非常簡單地翻譯,你可以看到 Kotlin 代碼對應(yīng)的 Java 代碼呈現(xiàn)。

 

  1. public abstract class Response { 
  2.    private Response() { 
  3.    } 
  4.  
  5.    // $FF: synthetic method 
  6.    public Response(DefaultConstructorMarker $constructor_marker) { 
  7.       this(); 
  8.    } 

你可能已經(jīng)猜到了,密封類專們用于繼承,所以它們是抽象的。不過他們變得與枚舉相似的?在這里,Kotlin 編譯器做了大量的工作,讓你可以在 when() 函數(shù)中將 Response 的子類用作分支。此外,Kotlin 提供了很大的靈活性來允許對密封類的繼承結(jié)構(gòu)可以被當(dāng)作數(shù)據(jù)聲明甚至對象來使用。

 

  1. fun sugar(response: Response) = when (response) { 
  2.     is Success -> ... 
  3.     is Error -> ... 
  4.     Timeout -> ... 

它不僅提供了非常徹底的表達式,還提供了自動類型轉(zhuǎn)換,因此你可以在不需要額外的轉(zhuǎn)換的情況下使用 Response 實例。

 

  1. fun sugar(response: Response) = when (response) { 
  2.     is Success -> println(response.body) 
  3.     is Error -> println("${response.code} ${response.message}"
  4.     Timeout -> println(response.javaClass.simpleName) 

你能想象一下,如果沒有一個 sealed 的功能,或者根本沒有 Kotlin ,它可能看起來是那么的丑陋和復(fù)雜?如果你忘記了 Java 語言的一些特性,請再次使用 IntelliJ IDEA Kotlin Bytecode ,但要坐下來使用 - 這可能會讓你暈倒。

 

  1. public final void sugar(@NotNull Response response) { 
  2.    Intrinsics.checkParameterIsNotNull(response, "response"); 
  3.    
  4.    String var3; 
  5.    if (response instanceof Success) { 
  6.       var3 = ((Success)response).getBody(); 
  7.       System.out.println(var3); 
  8.    } else if (response instanceof Error) { 
  9.       var3 = "" + ((Error)response).getCode() + ' ' + ((Error)response).getMessage(); 
  10.       System.out.println(var3); 
  11.    } else { 
  12.       if (!Intrinsics.areEqual(response, Timeout.INSTANCE)) { 
  13.          throw new NoWhenBranchMatchedException(); 
  14.       } 
  15.  
  16.       var3 = response.getClass().getSimpleName(); 
  17.       System.out.println(var3); 
  18.    } 

總結(jié)一下,我很高興在這種情況下使用 sealed 關(guān)鍵字,因為它讓我以類似于 Swift 的方式塑造我的 Kotlin 代碼。

使用 when()函數(shù)來排列

由于你已經(jīng)看到了 when()在 sealed 類中的用法,我決定再分享更多強大的功能。 想象一下,你必須實現(xiàn)一個接受兩個 enums 并產(chǎn)生一個不可變狀態(tài)的函數(shù)。

 

  1. enum class Employee { 
  2.     DEV_LEAD, 
  3.     SENIOR_ENGINEER, 
  4.     REGULAR_ENGINEER, 
  5.     JUNIOR_ENGINEER 
  6.  
  7. enum class Contract { 
  8.     PROBATION, 
  9.     PERMANENT, 
  10.     CONTRACTOR, 

enum class Employee 描述了在公司 XYZ 中可以找到的所有角色, enum class Contract 包含所有類型的雇傭合同。 基于這兩個 enums ,你應(yīng)該返回一個正確的 SafariBookAccess 。 而且,你的函數(shù)必須產(chǎn)生給定 enum 的所有排列的狀態(tài)。 第一步,我們來創(chuàng)建狀態(tài)生成函數(shù)的簽名。

 

  1. fun access(employee: Employee, 
  2.            contract: Contract): SafariBookAccess 

現(xiàn)在是時候定義 SafariBooksAccess 結(jié)構(gòu)體了,因為你已了解 sealed 關(guān)鍵字,這是使用它最適合的時機。封裝 SafariBookAccess 并不是必須的,但它是封裝不同情景下的 SafariBookAccess 的不同狀態(tài)的好方式。

 

  1. sealed class SafariBookAccess  
  2. data class Granted(val expirationDate: DateTime) : SafariBookAccess()  
  3. data class NotGranted(val error: AssertionError) : SafariBookAccess()  
  4. data class Blocked(val message: String) : SafariBookAccess() 

那么隱藏在 access() 函數(shù)后面的主要意圖是什么?全排列!讓我們羅列下。

 

  1. fun access(employee: Employee, 
  2.            contract: Contract): SafariBookAccess { 
  3.     return when (employee) { 
  4.         SENIOR_ENGINEER -> when (contract) { 
  5.             PROBATION -> NotGranted(AssertionError("Access not allowed on probation contract.")) 
  6.             PERMANENT -> Granted(DateTime()) 
  7.             CONTRACTOR -> Granted(DateTime()) 
  8.         } 
  9.         REGULAR_ENGINEER -> when (contract) { 
  10.             PROBATION -> NotGranted(AssertionError("Access not allowed on probation contract.")) 
  11.             PERMANENT -> Granted(DateTime()) 
  12.             CONTRACTOR -> Blocked("Access blocked for $contract."
  13.         } 
  14.         JUNIOR_ENGINEER -> when (contract) { 
  15.             PROBATION -> NotGranted(AssertionError("Access not allowed on probation contract.")) 
  16.             PERMANENT -> Blocked("Access blocked for $contract."
  17.             CONTRACTOR -> Blocked("Access blocked for $contract."
  18.         } 
  19.         else -> throw AssertionError() 
  20.     } 

這個代碼很完美,但你能讓它更像 Kotlin 嗎?當(dāng)你每天對同事的 PR/MR 進行審查時會有什么建議嗎?你可能會寫一些這樣的評論:

  • 太多 when() 函數(shù)。使用 Pair 來避免嵌套。
  • 改變枚舉參數(shù)的順序,定義 Pair() 對象來讓它更易讀。
  • 合并重復(fù)的 return。
  • 改為一個表達式函數(shù)。

 

  1. fun access(contract: Contract, 
  2.            employee: Employee) = when (Pair(contract, employee)) { 
  3.     Pair(PROBATION, SENIOR_ENGINEER), 
  4.     Pair(PROBATION, REGULAR_ENGINEER), 
  5.     Pair(PROBATION, JUNIOR_ENGINEER) -> NotGranted(AssertionError("Access not allowed on probation contract.")) 
  6.     Pair(PERMANENT, SENIOR_ENGINEER), 
  7.     Pair(PERMANENT, REGULAR_ENGINEER), 
  8.     Pair(PERMANENT, JUNIOR_ENGINEER), 
  9.     Pair(CONTRACTOR, SENIOR_ENGINEER) -> Granted(DateTime(1)) 
  10.     Pair(CONTRACTOR, REGULAR_ENGINEER), 
  11.     Pair(CONTRACTOR, JUNIOR_ENGINEER) -> Blocked("Access for junior contractors is blocked."
  12.     else -> throw AssertionError("Unsupported case of $employee and $contract"

現(xiàn)在它看起來更整潔,但 Kotlin 還有語法糖可以完全省略對 Pair 的定義。棒!

 

  1. fun access(contract: Contract, 
  2.            employee: Employee) = when (contract to employee) { 
  3.     PROBATION to SENIOR_ENGINEER, 
  4.     PROBATION to REGULAR_ENGINEER -> NotGranted(AssertionError("Access not allowed on probation contract.")) 
  5.     PERMANENT to SENIOR_ENGINEER, 
  6.     PERMANENT to REGULAR_ENGINEER, 
  7.     PERMANENT to JUNIOR_ENGINEER, 
  8.     CONTRACTOR to SENIOR_ENGINEER -> Granted(DateTime(1)) 
  9.     CONTRACTOR to REGULAR_ENGINEER, 
  10.     PROBATION to JUNIOR_ENGINEER, 
  11.     CONTRACTOR to JUNIOR_ENGINEER -> Blocked("Access for junior contractors is blocked."
  12.     else -> throw AssertionError("Unsupported case of $employee and $contract"

這個結(jié)構(gòu)讓我的生活變得輕松,也讓 Kotlin 代碼讀寫變得容易,我希望你也覺得這很有用。但它是不是不能用于三元組呢?答案是肯定的。

  1. Triple(enum1, enum2, enum3) == enum1 to enum2 to enum3 

以上就是第 1 部分的全部內(nèi)容,如果你仍然很有興趣,請繼續(xù)閱讀第 2 部分。干杯!

責(zé)任編輯:未麗燕 來源: 開源中國翻譯文章
相關(guān)推薦

2021-02-20 16:01:26

Github前端開發(fā)

2020-12-12 13:50:16

云開發(fā)

2021-01-27 13:54:05

開發(fā)云原生工具

2018-06-24 16:39:28

Tomcat異常線程

2021-06-10 08:15:49

CSS 文字動畫技巧

2021-03-25 06:12:55

SVG 濾鏡CSS

2021-10-28 19:35:02

代碼main方法

2012-05-22 10:12:59

jQuery

2022-06-15 07:21:47

鼠標(biāo)指針交互效果CSS

2022-08-15 22:34:47

Overflow方向裁切

2023-05-15 09:16:18

CSSCSS Mask

2017-08-01 00:52:07

kafka大數(shù)據(jù)消息總線

2012-06-19 16:49:19

Web開發(fā)

2024-03-18 08:14:07

SpringDAOAppConfig

2013-08-28 09:46:09

Debian LinuLinux發(fā)行版

2010-04-09 11:24:59

Oracle 排序

2021-11-17 10:45:58

Chrome 95新特性前端

2015-10-28 13:57:29

融合架構(gòu)華三UIS

2022-07-11 13:09:26

mmapLinux

2015-03-12 10:46:30

代碼代碼犯罪
點贊
收藏

51CTO技術(shù)棧公眾號