導入 THE キーワードは、Swift 5.1 で導入されました。 keyword は Swift 5.6 で導入されました。これらのキーワードは、次のように、関数のパラメータと型の定義の前に使用できます。 some any protocol P {} struct S: P {} // 'any P' is an explicit existential type. let p: any P = S() // 'some P' is an opaque type. let p: some P = S() func f(_ p: any P) {} func f(_ p: some P) {} SWIFT5では、 キーワードは、実存型を明示的に表すために使用できます. Starting from Swift 6, existential types are required to be explicitly spelled with the キーワード any any 透明型は、特定のコンクリート型を定義することなく、期待される返信型を記述するのに役立ちます. This way, the compiler can get access to the actual type information and can potentially perform optimizations in this context. 実存型は、プロトコルに合致するすべての値を格納することができ、値の型は動的に変化し、ダイナミックなメモリ割り当てを必要とする。 いくつかのキーワードを理解する opacous result type is an implicit generic placeholder satisfied by the implementation, so you can think of this: opacous result type is an implicit generic placeholder satisfied by the implementation. Keyword represents an opacous type. An opacous result type is an implicit generic placeholder satisfied by the implementation, so you can think of this: some protocol P {} struct S1 : P {} func f() -> some P { return S1() } ここで重要な取り出しは、タイプを生成する機能であるということです。 specifically returns a value of a singular, concrete type adhering to 関数が複数のコンプライアンス型を返そうとすると、複数の型によって暗示的な一般的な場所保持者を満たすことができないため、コンパイラーエラーが発生します。 P P struct F1: P {} struct F2: P {} // error: Function declares an opaque return type, but the return // statements in its body do not have matching underlying types. func f(_ value: Bool) -> some P { if value { return F1() } else { return F2() } } 透明なタイプがプロトコルリターンタイプに比べて提供する利点を検討しましょう。 Opaque result types can be used with PATs. The main limitation of using protocols is that protocols with associated types cannot be used as actual types. This means that the following code doesn’t compile: func collection() -> Collection { return ["1", "2", "3"] } As for opaque types, they are merely generic placeholders that can be used in such scenarios: // protocol Collection<Element> : Sequence func collection() -> some Collection { return ["1", "2", "3"] } Opaque result types have identity. Because opaque types guarantee that only one type will be returned, the compiler knows that a function must return the same type on several calls: func method() -> some Equatable { return "method" } let x = method() let y = method() print(x == y) // true Opaque result types compose with generic placeholders. Contrary to conventional protocol-typed values, opaque result types integrate effectively with standard generic placeholders. For instance: protocol P { var message: String { get } } struct M: P { var message: String } func makeM() -> some P { return M(message: "message") } func bar<T: P, U: P>(_ p1: T, _ p2: U) -> Bool { return p1.message == p2.message } let m1 = makeM() let m2 = makeM() print(bar(m1, m2)) However, it doesn’t work if make returns different types based on protocol . M() P protocol P { var message: String { get } } struct M: P { var message: String } struct T: P { var message: String } // error: function declares an opaque return type 'some P', but the return statements in its body do not have matching underlying types func makeM() -> some P { if .random() { return M(message: "M message") } else { return T(message: "T message") } } すべてのキーワードを理解 次のような例を挙げてみましょう.I have a 議定書とこの議定書の2つの具体的な実施について。 Drawable protocol Drawable { func draw() } struct Line: Drawable { let x1: Int let y1: Int let x2: Int let y2: Int func draw() { print("Draw Line") } } struct Point: Drawable { let x: Int let y: Int func draw() { print("Point") } } 二つの構造物体があるので、 そして , accordingly. Let's create a variable and store a. 変数を作成し、 対象: Line Point Drawable var p1: any Drawable = Line(x1: 0, y1: 0, x2: 5, y2: 5) // 'any Drawable' is an explicit existential type p1.draw() // print "Draw Line" p1 = Point(x: 0, y: 0) p1.draw() // print "Point" ランタイム中にさまざまな実装間を切り替えることができます. Let's consider another example: let array: [any Drawable] = [ Line(x1: 0, y1: 0, x2: 5, y2: 5), Line(x1: 0, y1: 0, x2: 5, y2: 5), Point(x: 0, y: 0) ] 私たちが知っているように、数列内のいずれかの要素へのランダムアクセスを常時実現することは、それぞれの要素が同じメモリサイズを持っているため可能である。 print(MemoryLayout<Line>.size) // 32 print(MemoryLayout<Point>.size) // 16 それは可能なので、The 実存的コンテナは5つの機械単語をカプセル化し、物体に物体またはポインタを保存するために3つを割り当て、仮想テーブルへのポインタのための1つ、証人テーブルへのポインタのための1つを割り当てます。 any 実存的なコンテナには5つの機械単語(x64ビットシステムでは5 * 8 = 40)が必要です。 Value buffer is a space for the instance VWT is a pointer to Value Witness Table PWT is a pointer to the Protocol Witness Table プロトコルの値がコードで使用されるたびに、コンパイラは存在性コンテナと呼ばれるボックスを生成します. One box for one value. Since they can store any value whose type conforms to the protocol, and the type of the stored value can change dynamically, the existential container requires dynamic memory allocation if the value is not small enough to fit into a buffer of 3 machine words. プロトコルの種類がプロトコルに合致するすべての値を保存することができ、および保存された値の種類が動的に変化することができるので、存在性コンテナは、値が3マシン単語のバッファに適合するほど小さくない場合、ダイナミックメモリの割り当てが必要です。 集積分配と参照計算に加えて、存在性コンテナのすべての使用には、最適化できないポインター間接とダイナミックディスパッチが含まれます。 3 個の単語が 3 個のマシン単語に匹敵する場合に値を組み込むか、または値が 3 個のマシン単語を超える場合に ARC マネージド ボックスが作成されます。その後、値がボックスにコピーされ、ARC マネージド ボックスへのポインターがコンテナの最初の単語にコピーされます。残りの 2 個の単語は使用されません。 The Protocol Witness Table is an array that contains one entry for each protocol statically associated with the existential type. If the type of a value, let's say, is something like any other type. プロトコル証人テーブルは、あらゆるプロトコルに1つの入力を含むアレルギーです。 プロトコル証人テーブル(PWT)がある限り、プロトコルに該当するタイプの遵守を記述する限り、私たちは実存的なコンテナを作成し、それを渡し、ダイナミックな配送に使用することができます。 P & Q したがって、我々は存在性コンテナを持っており、プロトコル証言テーブルを持っています。しかし、我々はこの値が存在性コンテナにどこに保存されるべきかを知りません - それがコンテナに直接保存されているか、もしくは我々は単にバック内の値に参照している場合だけです。 で、 で、 で、 すべてのタイプにはそのようなテーブルがあり、そのタイプのインスタンスを作成し、値がストレージされる場所を決定する責任を負います - スタックまたはバック、等。 allocate copy destruct deallocate 今、我々は異なるサイズのパラメータを渡る問題を解決する固定サイズの容器を持っているし、この容器を移動する方法があります。 さて、少なくとも、プロトコルで指定されたように、コンテナに保存された値の必要なメンバーを呼び出したい(イニシアライザー、属性 - ストレージまたは計算、関数、サブスクリプト)。 しかし、それぞれの対応型は、これらのメンバーを異なる方法で実装することができます。例えば、一部は、それを直接定義することによって方法の要件を満たす可能性がありますが、別のクラスは、スーパークラスから方法を継承することによってそれを満たす可能性があります。 この多様性を扱うことは、プロトコル証人テーブル(PWT)の主な目的です. それぞれのプロトコルコンプライアンスのための正確に1つのテーブルがあります. それには、プロトコルの要件の実装を指す機能ポインタのセットが含まれています. 関数は異なる場所に位置する場合がありますが、PWTの位置は、それに該当するプロトコルにとってユニークです. As a result, the caller can inspect the PWT of the container, use it to locate the implementation of the protocol's methods, and invoke them. コンパイラとランタイムは、存在を満たす具体的なオブジェクトにどのくらいのメモリが割り当てられるかを事前に決定することができないため、存在するものは使用するのに比較的高価であることを知ることが重要です。 コンパイラとランタイムは、存在を満たす具体的なオブジェクトにどのくらいのメモリが割り当てられるかを事前に決定することができないため、存在するものは使用するのに比較的高価であることを知ることが重要です。 概要 我々は、その間の違いを考慮した。 そして 一方で、私たちの一般的なコードの構文と可読性を大幅に向上させた一方で、より効率的な方法で一般的なコードを作成するための新しい方法を導入しました。 some any 読んでくれてありがとう。