我如何區分 Swift 中的通用值是什么?
例如,值 'T' 有什么作用,值 'E' 有什么作用?
func ??<T, E>(result: Result<T, E>, handleError: (E) -> T) -> T {
switch result {
case let .success(value):
return value
case let .failure(error):
return handleError(error)
}
}
uj5u.com熱心網友回復:
值“T”有什么作用,值“E”有什么作用?
它們不是“值”,而是型別的名稱——與 String 或 Int 之類的術語相當。事實上,T 可以是String 或 Int。但 E 必須是某種型別的錯誤。
因此<T, E>,出現兩次的短語僅表示 T 和 E 是其真實型別的通用占位符這一事實。當有人真正呼叫這個??函式時,呼叫者會弄清楚 T 和 E 到底是什么。這稱為決議泛型。
因此,讓我們想象一下,我們??以將 T 決議為 String 并將 E 決議為 Error 的方式呼叫。然后在編譯器的腦海中,我們會有這樣的:
func ??(result: Result<String, Error>, handleError: (Error) -> String) -> String {
switch result {
case let .success(value):
return value
case let .failure(error):
return handleError(error)
}
}
所以現在我們可以閱讀函式宣告了。它說:“你給我兩個引數。一個, result:, 必須是一個 Result 列舉,它的成功型別是字串,失敗型別是錯誤。另一個handleError:,, 必須是一個接受錯誤并回傳一個字串的函式。我會回傳一個字串給你。”
除,當然,這只是一個出路的方式來解決T和E.他們站在了無限多的實際型別將取決于如何解決的編譯時間,??實際被呼叫。所以這就是你的答案;這就是他們所做的。它們是代表將在編譯時決議的真實型別的占位符。
事實上,為了演示,我將以將 T 決議為 String 并將 E 決議為 Error 的方式呼叫您的函式(盡管我將重命名您的函式myFunc以使名稱合法):
func myFunc<T, E>(result: Result<T, E>, handleError: (E) -> T) -> T {
switch result {
case let .success(value):
return value
case let .failure(error):
return handleError(error)
}
}
enum MyError : Error { case oops }
let r = Result<String, Error> { throw MyError.oops }
let output = myFunc(result:r) { err in "Ooops" }
print(output) // Ooops
腳注:請注意,您的函式不能真正被呼叫??,因為該名稱已被使用。稱呼它可能更好foo(在這些情況下通常是無意義的名稱)。
uj5u.com熱心網友回復:
@matt 的回答說明了這一點,所以我想我會添加一些更高級別的評論。
型別引數命名
對這些泛型型別引數使用單個字符是 Java 和 C# 的遺留約定,但不必如此簡潔。在此示例中,如果您查看對型別 ( Result)的主要約束,請注意它們使用Success和Failure。在這里使用這些可以更清楚地了解這個函式的意圖:
func ??<Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success
因此,一個函式需要:
- a
Result可以包含 aSuccess或 aFailure,以及 - 一個接受 a
Failure并回傳 a的閉包Success
并回傳:
- 一種
Success
實作不受型別系統約束
請注意,由于這些型別都沒有包含在Optional此函式的實作中,因此幾乎完全受限(盡管有副作用)。
以看似匹配的最簡單函式為例:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
return Success()
}
嘗試編譯它會出現以下錯誤:
main.swift:2:12: error: type 'Success' has no member 'init'
return Success()
^~~~~~~
由于Success型別在 中完全不受約束Result,所以我們實際上并不知道如何在函式內部創建一個。
我們知道Result 可以包含 a Success,那么如果我們嘗試強行獲取它呢?
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
return result.get()
}
現在失敗并出現以下編譯器錯誤:
main.swift:2:12: error: call can throw, but it is not marked with 'try' and the error is not handled
return result.get()
^
由于此函式已明確表示它不會拋出,并且如果它不包含Result.get()則將拋出Failure包含的Success。
Success擺脫 a的另一種方法Result是模式匹配,讓我們看看如何匹配單個的列舉案例模式if:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
if case let .success(success) = result {
return success
}
}
When attempting this, the compilation error is (quite sensibly):
main.swift:5:1: error: missing return in a function expected to return 'Success'
}
^
So we need to also handle the case when a Result contains a Failure. Let's try with another pattern match, using the provided handleError closure:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
if case let .success(success) = result {
return success
}
if case let .failure(failure) = result {
return handleError(failure)
}
}
This still gives the same error as the previous attempt, as the logic could still fall through in this case (this seems unlikely, but this could be subject to a kind of time-of-check to time-of-use bug).
Let's attempt it again, but matching both patterns in a switch:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
switch result {
case let .success(success):
return success
case let .failure(failure):
return handleError(failure)
}
}
There we go, compiling without error.
As is obvious, this is the original function, as provided in your question.
Now that we've arrived back here, can we trim down this implementation? We could try something like:
func ?? <Success, Failure>(result: Result<Success, Failure>, handleError: (Failure) -> Success) -> Success {
switch result {
case let .success(success):
return success
}
}
but this provides this compilation error:
main.swift:2:5: error: switch must be exhaustive
switch result {
^
main.swift:2:5: note: add missing case: '.failure(_)'
switch result {
^
which indicates that we need that .failure(_) case to match all possible outcomes of the result.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/322518.html
標籤:迅速
