次のコードでは、x
がSpecialController
かどうかをテストします。そうである場合、currentValue
をSpecialValue
として取得します。これどうやってやるの?キャストでない場合は、他のテクニックを使用します。
そこの最後の行はコンパイルされません。エラーがあります:Selfまたは関連する型の要件があるため、プロトコル「SpecialController」は一般的な制約としてのみ使用できます。
protocol SpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
...
var x: AnyObject = ...
if let sc = x as? SpecialController { // does not compile
残念ながら、Swiftは現在、実際の型として関連付けられた型を持つプロトコルの使用をサポートしていません。ただし、これは 技術的に可能 コンパイラが行うことであり、- 言語の将来のバージョンで実装されるかもしれません 。
あなたの場合の簡単な解決策は、SpecialController
の派生元である「シャドウプロトコル」を定義し、タイプがそれを消去するというプロトコル要件を通じてcurrentValue
にアクセスできるようにすることです。
// This assumes SpecialValue doesn't have associated types – if it does, you can
// repeat the same logic by adding TypeErasedSpecialValue, and then using that.
protocol SpecialValue {
// ...
}
protocol TypeErasedSpecialController {
var typeErasedCurrentValue: SpecialValue? { get }
}
protocol SpecialController : TypeErasedSpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
extension SpecialController {
var typeErasedCurrentValue: SpecialValue? { return currentValue }
}
extension String : SpecialValue {}
struct S : SpecialController {
var currentValue: String?
}
var x: Any = S(currentValue: "Hello World!")
if let sc = x as? TypeErasedSpecialController {
print(sc.typeErasedCurrentValue as Any) // Optional("Hello World!")
}
[修正のために編集:: SpecialValue
ではなく= SpecialValue
]
これは不可能です。 SpecialValueController
は概念的には「不完全な型」であり、コンパイラーはこれを知ることができません。 SpecialValueType
、それはによって制約されるSpecialValue
ですが、採用しているクラスによって決定されるまで不明です。したがって、これは情報が不十分な本当にプレースホルダーです。 as?
- nessを確認できません。
SpecialController
の-concreteタイプを使用してSpecialValueController
を採用する基本クラスがあり、採用しているクラスから継承する複数の子クラスがある場合は、ある程度のポリモーフィズムを求める。
SpecialController
は単一の型ではないため、これは機能しません。関連する型は、ジェネリックの一種と考えることができます。 SpecialController
がSpecialValueType
であるInt
は、SpecialController
がSpecialValueType
であるString
とは完全に異なる型です。これは、Optional<Int>
がOptional<String>
とは完全に異なる型であるようにです。
このため、SpecialValueType
にキャストしても意味がありません。これは、関連する型を覆い隠し、(たとえば)SpecialController
をSpecialValueType
がInt
にして、SpecialController
をSpecialValueType
にして、 String
が必要です。
コンパイラーが示唆するように、SpecialController
を使用できる唯一の方法は、一般的な制約としてです。 T
はT
でなければならないという制約のもとで、SpecialController
のジェネリック関数を使用できます。 T
のドメインは、SpecialController
に関連付けられたタイプやInt
を持つタイプなど、String
のさまざまな具象タイプすべてに及ぶようになりました。関連付けられている可能性のある型ごとに、別個のSpecialController
があり、拡張すると、別個のT
があります。
Optional<T>
のアナロジーをさらに引き出すため。あなたがしようとしていることが可能だったと想像してみてください。次のようになります。
func funcThatExpectsIntOptional(_: Int?) {}
let x: Optional<String> = "An optional string"
// Without its generic type parameter, this is an incomplete type. suppose this were valid
let y = x as! Optional
funcThatExpectsIntOptional(y) // boom.