成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

語法糖會導致分號的悲劇。—— Alan J. Perlis

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

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

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

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

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

來看看下面的示例代碼。

 

  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() 

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

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

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

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

第二步。將 Kotlin 字節碼反編譯成 Java 代碼

經過這樣非常簡單地翻譯,你可以看到 Kotlin 代碼對應的 Java 代碼呈現。

 

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

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

 

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

它不僅提供了非常徹底的表達式,還提供了自動類型轉換,因此你可以在不需要額外的轉換的情況下使用 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 ,它可能看起來是那么的丑陋和復雜?如果你忘記了 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.    } 

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

使用 when()函數來排列

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

 

  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 ,你應該返回一個正確的 SafariBookAccess 。 而且,你的函數必須產生給定 enum 的所有排列的狀態。 第一步,我們來創建狀態生成函數的簽名。

 

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

現在是時候定義 SafariBooksAccess 結構體了,因為你已了解 sealed 關鍵字,這是使用它最適合的時機。封裝 SafariBookAccess 并不是必須的,但它是封裝不同情景下的 SafariBookAccess 的不同狀態的好方式。

 

  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() 函數后面的主要意圖是什么?全排列!讓我們羅列下。

 

  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 嗎?當你每天對同事的 PR/MR 進行審查時會有什么建議嗎?你可能會寫一些這樣的評論:

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

 

  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"

現在它看起來更整潔,但 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"

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

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

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

責任編輯:未麗燕 來源: 開源中國翻譯文章
相關推薦

2021-02-20 16:01:26

Github前端開發

2021-06-10 08:15:49

CSS 文字動畫技巧

2021-10-28 19:35:02

代碼main方法

2020-12-12 13:50:16

云開發

2021-01-27 13:54:05

開發云原生工具

2018-06-24 16:39:28

Tomcat異常線程

2021-03-25 06:12:55

SVG 濾鏡CSS

2012-05-22 10:12:59

jQuery

2022-08-15 22:34:47

Overflow方向裁切

2023-05-15 09:16:18

CSSCSS Mask

2022-06-15 07:21:47

鼠標指針交互效果CSS

2013-08-28 09:46:09

Debian LinuLinux發行版

2017-08-01 00:52:07

kafka大數據消息總線

2022-07-11 13:09:26

mmapLinux

2012-06-19 16:49:19

Web開發

2024-03-18 08:14:07

SpringDAOAppConfig

2009-08-26 17:53:31

C# DropDown

2010-04-09 11:24:59

Oracle 排序

2021-11-17 10:45:58

Chrome 95新特性前端

2015-10-28 13:57:29

融合架構華三UIS
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 毛片高清| 免费99视频 | 看片网站在线 | 日本不卡免费新一二三区 | 天天看天天干 | 欧美日韩在线视频一区 | 欧美午夜精品理论片a级按摩 | 亚洲精品亚洲人成人网 | 国产片一区二区三区 | 手机av在线 | 国产精品一区二区不卡 | www.久久久.com | 国色天香成人网 | 日韩欧美大片 | 欧美一区二区三区小说 | 日韩专区中文字幕 | 久久高清| 欧美日韩精品国产 | 国产精品一区二区av | 性一区 | av在线一区二区三区 | 中文字幕在线观看www | 久久久做 | 中文字幕第十页 | 中文天堂在线一区 | 欧美一区永久视频免费观看 | 91影库 | 久久99精品国产99久久6男男 | 欧美精品在线播放 | 日韩免费高清视频 | 欧美一区在线视频 | 一级做a爰片久久毛片 | 久久6视频 | 91xxx在线观看 | 不卡一区二区三区四区 | 亚洲高清av | 精品中文字幕在线 | 天天干天天操天天爽 | 日日干日日操 | 亚洲欧美一区二区三区视频 | 成人网在线观看 |