網站首頁 編程語言 正文
Swift 的類型推斷能力從一開始就是語言的核心部分,它極大地減少了我們在聲明有默認值的變量和屬性時手動指定類型的工作。例如,表達式var number = 7
不需要包含任何類型注釋,因為編譯器能夠推斷出值7
是一個Int
,我們的number
變量應該被相應的類型化。
作為 Xcode 13.3 的一部分而一起發布的 Swift 5.6,通過引入 "類型占位符(type placeholders) "的概念,繼續擴展這些類型推理能力,這在處理集合和其他通用類型時非常有用。
例如,假設我們想創建一個Combine
里面具有默認整數值的 CurrentValueSubject
的實例。關于如何做到這一點的初步想法可能是簡單地將我們的默認值傳遞給該主體的初始化器,然后將結果存儲在本地的一個let
聲明的屬性中(就像創建一個普通的Int
值時一樣)。然而,這樣做會給我們帶來以下編譯器錯誤:
// Error: "Generic parameter 'Failure' could not be inferred" // Error: “無法被推斷出泛型的`Failure`參數 ” let counterSubject = CurrentValueSubject(0)
這是因為CurrentValueSubject
是一個泛型類型,實例化時不僅需要Output
類型,還需要Failure
類型——這是該主體能夠拋出的錯誤類型。
因為我們不希望我們的主體在這種情況下拋出任何錯誤,所以我們會給它一個Failure
類型的值Never
(這是在 Swift 中使用 Combine
的一個常見慣例)。但為了做到這一點,在 Swift 5.6 之前,我們需要明確地指定我們的Int
輸出類型——像這樣:
let counterSubject = CurrentValueSubject<Int, Never>(0)
不過從 Swift 5.6 開始,這種情況就不存在了——因為我們現在可以使用一個類型占位符來表示我們主體的Output
類型,這讓我們再次利用編譯器為我們自動推斷出該類型,就像在聲明一個普通的Int
值一樣:
let counterSubject = CurrentValueSubject<_, Never>(0)
這很好,但可以說這并不是 swift 里面很大的改進。畢竟,我們用_
代替Int
只是節省了兩個字符,而且手動指定像Int
這樣的簡單類型也不是一開始就有問題的。
**但現在讓我們看看這個功能如何擴展到更復雜的類型,這是它真正開始發光的地方。**例如,假設我們的項目包含以下函數,讓我們加載一個用戶注解的PDF文件:
func loadAnnotatedPDF(named: String) -> Resource<PDF<UserAnnotations>> { ... }
上面的函數使用了一個相當復雜的泛型作為它的返回類型,這可能是因為我們需要在多個地方中重復使用我們的Resource
類型,也因為我們選擇了使用*幻象類型*來指定我們當前處理的是哪種PDF。
現在讓我們看看,如果我們在創建主體時調用上述函數,而不是僅僅使用一個簡單的整數,那么我們之前基于CurrentValueSubject
的代碼會是什么樣子:
// Before Swift 5.6: let pdfSubject = CurrentValueSubject<Resource<PDF<UserAnnotations>>, Never>( loadAnnotatedPDF(named: name) ) // Swift 5.6: let pdfSubject = CurrentValueSubject<_, Never>( loadAnnotatedPDF(named: name) )
這是一個相當大的改進啊 基于 Swift 5.6 的版本不僅為我們節省了一些輸入,而且由于 pdfSubject
的類型現在完全來自 loadAnnotatedPDF
函數,這可能會使該函數(及其相關代碼)的迭代更加容易——因為如果我們改變該函數的返回類型,需要更新的手動類型注釋將減少。
不過,值得指出的是,在上述情況下,還有另一種方法可以利用Swift的類型推理能力——那就是使用類型別名,而不是類型占位符。例如,我們可以在這里定義一個UnfailingValueSubject
類型別名,我們可以用它來輕松地創建不會產生任何錯誤的主體:
typealias UnfailingValueSubject<T> = CurrentValueSubject<T, Never>
有了上述內容,我們現在就可以在沒有任何泛型注解的情況下創建我們的pdfSubject
了——因為編譯器能夠推斷出T
指的是什么類型,而且失敗類型Never
已經被硬編碼到我們的新類型別名中:
let pdfSubject = UnfailingValueSubject(loadAnnotatedPDF(named: name))
但這并不意味著類型別名在通常情況下都比類型占位符好,因為如果我們要為每種特定情況定義新的類型別名,那么這也會使我們的代碼庫變得更加復雜。有時,在內聯中指定所有的東西(比如使用類型占位符時)絕對是個好辦法,因為這可以讓我們定義完全獨立的表達式。
在我們總結之前,讓我們也來看看類型占位符是如何與集合字面量(literals)一起使用的——例如在創建一個字典時。在這里,我們選擇手動指定我們的字典的 Key
類型(為了能夠使用點語法來指代枚舉的各種情況),同時為該字典的值使用一個類型占位符:
enum UserRole { case local case remote } let latestMessages: [UserRole: _] = [ .local: "", .remote: "" ]
這就是類型占位符——Swift 5.6 中引入的一個新功能,在處理稍微復雜的通用類型時,它可能真的很有用。但值得指出的是,這些占位符只能在調用站點使用,而不是在指定函數或計算屬性的返回類型時使用。
總結
原文鏈接:https://juejin.cn/post/7108291937722957860
相關推薦
- 2022-05-18 C語言程序環境和預處理詳解分析_C 語言
- 2022-04-12 如何在Python中編寫接口和請求外部接口_python
- 2023-04-24 Android布局控件View?ViewRootImpl?WindowManagerService關
- 2022-02-28 npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT
- 2023-01-03 Kotlin文件讀寫與SharedPreferences存儲功能實現方法_Android
- 2022-10-26 python?NumPy讀取和保存點云數據實現_python
- 2022-11-16 詳解Python中range()與xrange()的區別_python
- 2022-12-11 React中Redux核心原理深入分析_React
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支