[解決済み】Swift(UI)の "some "キーワードとは?)
質問
新しい SwiftUIチュートリアル は次のようなコードを持っています。
struct ContentView: View {
var body: some View {
Text("Hello World")
}
}
2行目の単語
some
という単語が、キーワードであるかのように強調されています。
Swift 5.1 には
some
をキーワードとして持っていないようで、他の単語である
some
という単語は、通常型が行くところに行くので、そこで何をすることができるのかわかりません。Swiftの新しい未発表のバージョンがあるのでしょうか?私が知らない方法で型に使用されている関数なのでしょうか?
というキーワードは何を意味するのでしょうか?
some
は何をするのでしょうか?
どのように解決するのですか?
some View
は
不透明な結果タイプ
で紹介されているように
SE-0244
で導入され、Xcode 11 の Swift 5.1 で利用可能です。これは、"reverse" 一般的なプレースホルダーであると考えることができます。
呼び出し元によって満たされる通常のジェネリックプレースホルダーとは異なります。
protocol P {}
struct S1 : P {}
struct S2 : P {}
func foo<T : P>(_ x: T) {}
foo(S1()) // Caller chooses T == S1.
foo(S2()) // Caller chooses T == S2.
不透明な結果型は、暗黙の汎用プレースホルダーで 実装 と考えることができますので
func bar() -> some P {
return S1() // Implementation chooses S1 for the opaque result.
}
をこのように表示します。
func bar() -> <Output : P> Output {
return S1() // Implementation chooses Output == S1.
}
実際、この機能の最終的な目標は、より明示的な形でリバース・ジェネリックを可能にすることで、例えば
-> <T : Collection> T where T.Element == Int
.
詳細については、この投稿を参照してください。
.
ここから得られる主なことは、関数が返す
some P
を返すものは、特定の
シングル
に準拠した具体的な型である。
P
. 関数内で異なる適合する型を返そうとすると、コンパイラーエラーが発生します。
// error: Function declares an opaque return type, but the return
// statements in its body do not have matching underlying types.
func bar(_ x: Int) -> some P {
if x > 10 {
return S1()
} else {
return S2()
}
}
暗黙のジェネリックプレースホルダーは複数の型では満たすことができないため
を返す関数とは対照的です。
P
を返す関数とは対照的で、これは
ともに
S1
と
S2
を表すので、任意の
P
適合する値です。
func baz(_ x: Int) -> P {
if x > 10 {
return S1()
} else {
return S2()
}
}
さて、では不透明な結果型はどのような利点があるのでしょうか?
-> some P
はプロトコルの戻り値型よりも
-> P
?
1. 不透明な結果型をPATで使用することができる
プロトコルの現在の主な制限は、PAT (関連付けられた型を持つプロトコル) が実際の型として使用できないことです。これはおそらく言語の将来のバージョンで解除される制限ですが、不透明な結果型は事実上単なる一般的なプレースホルダーなので、今日PATと一緒に使用することができます。
つまり、次のようなことができるのです。
func giveMeACollection() -> some Collection {
return [1, 2, 3]
}
let collection = giveMeACollection()
print(collection.count) // 3
2. 不透明な結果型は同一性を持つ
不透明な結果型は単一の具象型を返すことを強制するため、コンパイラは同じ関数への2回の呼び出しが同じ型の2つの値を返さなければならないことを知ります。
これは、次のようなことができることを意味します。
// foo() -> <Output : Equatable> Output {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
let x = foo()
let y = foo()
print(x == y) // Legal both x and y have the return type of foo.
これは合法的なものです。
x
と
y
は同じ具象型を持ちます。これは
==
では、両方のパラメータが
Self
.
protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
}
これは、具体的な適合型と同じ型である2つの値を期待することを意味します。たとえ
Equatable
が型として使用可能であったとしても、二つの任意の
Equatable
に準拠した値を互いに比較することはできないでしょう。
func foo(_ x: Int) -> Equatable { // Assume this is legal.
if x > 10 {
return 0
} else {
return "hello world"
}
}
let x = foo(20)
let y = foo(5)
print(x == y) // Illegal.
コンパイラは二つの任意の
Equatable
の値が同じ基礎となる具象型を持つことを証明できないからです。
同じように、別の不透明な型を返す関数を導入すれば
// foo() -> <Output1 : Equatable> Output1 {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
// bar() -> <Output2 : Equatable> Output2 {
func bar() -> some Equatable {
return "" // The opaque result type is inferred to be String.
}
let x = foo()
let y = bar()
print(x == y) // Illegal, the return type of foo != return type of bar.
この例では
foo
と
bar
を返す
some Equatable
また、その逆の一般的なプレースホルダーである
Output1
と
Output2
は異なるタイプによって満たされる可能性があります。
3. 不透明な結果タイプは一般的なプレースホルダーと合成される
通常のプロトコル型値とは異なり、不透明な結果型は通常の一般的なプレースホルダーなどとうまく組み合わせることができます。
protocol P {
var i: Int { get }
}
struct S : P {
var i: Int
}
func makeP() -> some P { // Opaque result type inferred to be S.
return S(i: .random(in: 0 ..< 10))
}
func bar<T : P>(_ x: T, _ y: T) -> T {
return x.i < y.i ? x : y
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Legal, T is inferred to be the return type of makeP.
これは、もし
makeP
を返しただけではうまくいきません。
P
として、2つの
P
の値が異なる具象型を持つ可能性があるためです。
struct T : P {
var i: Int
}
func makeP() -> P {
if .random() { // 50:50 chance of picking each branch.
return S(i: 0)
} else {
return T(i: 1)
}
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Illegal.
なぜ具象型ではなく不透明な結果型を使用するのですか?
この時点で、なぜコードを次のように書かないのか、自分自身で考えているかもしれません。
func makeP() -> S {
return S(i: 0)
}
さて、不透明な結果型を使用することで、型を
S
で提供されるインターフェイスのみを公開することで、実装の詳細とすることができます。
P
によって提供されるインターフェイスのみを公開することで、関数に依存するコードを壊すことなく、後で具象型を変更する柔軟性を与えています。
例えば、置き換えることができます。
func makeP() -> some P {
return S(i: 0)
}
を使っています。
func makeP() -> some P {
return T(i: 1)
}
を呼び出すコードを壊さずに
makeP()
.
参照 不透明な型」セクションを参照してください。 言語ガイドの Swift の進化に関する提案 を参照してください。
関連
-
[解決済み] Xcode 8 シェルスクリプト呼び出しエラー
-
[解決済み] Swift 5でXOR?
-
[解決済み] Swift - 呼出しの余分な引数
-
[解決済み] SwiftからObjective-Cのコードを呼び出すにはどうしたらいいですか?
-
[解決済み] Swiftで#pragmaマーク?
-
[解決済み] Swift Betaのパフォーマンス:配列のソート
-
[解決済み] Swiftの'open'キーワードは何ですか?
-
[解決済み】(Swiftで)オブジェクトの型を調べるには?)
-
[解決済み】swiftで変数のメモリアドレスを印刷する
-
[解決済み] 非同期ネットワークリクエストのswift forループの実行が終了するまで待つ
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】インスタンスメンバを型で使用することができない
-
[解決済み] Swift 5でXOR?
-
[解決済み] Swiftでbase64StringをStringに変換する方法とは?
-
[解決済み] Swift Optionals - 条件の変数バインディングはイニシャライザを必要とする
-
[解決済み] SwiftはPass By ValueかPass By Referenceか
-
[解決済み] swiftの"? "の意味は何ですか?[重複している]。
-
[解決済み] String型のenumを列挙する方法は?
-
[解決済み】Swiftでオブジェクトが与えられた型かどうかを確認する
-
[解決済み】コンパイラーエラー。Objective-C のセレクタを持つメソッドは、同じ Objective-C セレクタを持つ以前の宣言と競合しています。
-
[解決済み】Swiftで辞書に要素を追加する方法は?