関連する値のResult
型が.success
ジェネリックになるように、Swiftの新しい型を使用しようとしています。以下のかなり工夫されたサンプルコードは機能しますが、コンパイラが正しい型を推測できるように型キャストを単純化する方法はありT
ますか?
enum FetchError : Error {
case unknownKey
}
enum FetchKey {
case getWidth
case getName
}
func fetchValue<T>(_ key:FetchKey) -> Result<T, FetchError> {
switch key {
case .getName:
// Ideally I would like to just use: return .success("Johnny Appleseed")
return Result<String, FetchError>.success("Johnny Appleseed") as! Result<T, FetchError>
case .getWidth:
return Result<Double, FetchError>.success(25.0) as! Result<T, FetchError>
@unknown default:
return .failure(.unknownKey)
}
}
// This explicit type declaration is also required.
let r:Result<String, FetchError> = fetchValue(.getName)
print(r)
型キャストについてのあなたの質問に、あなたは間違いなくそれを単純化することができます:
case .getName:
return .success("Johnny Appleseed" as! T)
間違ったタイプを要求することがプログラミングエラーと見なされるべきであり(したがってクラッシュするはずである)、結果が外部ソースから得られることは決してない場合、これは問題ありません。データが外部ソースから取得される可能性がある場合は、データが間違っていることに応答してクラッシュすることはありません。
その場合、その種のエラーをモデル化する必要があります。
enum FetchError : Error {
case unknownKey
case invalidType
}
次に、(失敗する可能性のある)型変換を行う関数を追加することで、好みに非常に近い構文を作成できます。
func fetchValue<Value>(_ key:FetchKey) -> Result<Value, FetchError> {
func checkType(_ value: Any) -> Result<Value, FetchError> {
guard let value = value as? Value else { return .failure(.invalidType) }
return .success(value)
}
switch key {
case .getName: return checkType("Johnny Appleseed")
case .getWidth: return checkType(25.0)
@unknown default: return .failure(.unknownKey)
}
}
そうは言っても、必要な型注釈の醜さを避けるために、このようにします。
func fetch<Value>(_: Value.Type, forKey key: FetchKey) -> Result<Value, FetchError> { ... }
let r = fetch(String.self, forKey: .getName)
これはのパターンに従いますCodable
。
いくつかの異なる方法で、ソリューション全体を1か所にまとめました。
enum FetchError : Error {
case unknownKey
case invalidType
}
enum FetchKey {
case width
case name
}
func fetch<Value>(_: Value.Type, forKey key: FetchKey) -> Result<Value, FetchError> {
func checkType(_ value: Any) -> Result<Value, FetchError> {
guard let value = value as? Value else { return .failure(.invalidType) }
return .success(value)
}
switch key {
case .name: return checkType("Johnny Appleseed")
case .width: return checkType(25.0)
@unknown default: return .failure(.unknownKey)
}
}
Resultにラップするよりも、投げた方が少しいいと思います。つまりcheckType
、1つの場所に簡単に移動でき、必要な構文に非常に近づくことができます。
func fetch<Value>(_: Value.Type, forKey key: FetchKey) throws -> Value {
func checkType(value: () throws -> Any) throws -> Value {
guard let value = try value() as? Value else { throw FetchError.invalidType }
return value
}
return try checkType {
switch key {
case .name: return "Johnny Appleseed"
case .width: return 25.0
@unknown default: throw FetchError.unknownKey
}
}
}
エラーを気にしない場合は、Optionalを使用するとこれが少し簡単になります。
func fetch<Value>(_: Value.Type, forKey key: FetchKey) -> Value? {
func _fetch() -> Any? {
switch key {
case .name: return "Johnny Appleseed"
case .width: return 25.0
@unknown default: return nil
}
}
return _fetch() as? Value
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加