Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
some / any / opaque type
Swift 5.7 以降、プロトコル型の扱い方として『some』(不透明型)と『any』(存在型)の2つのキーワードが導入されました。どちらもプロトコルを型として使う仕組みです。
構文
// some: 不透明型(戻り値が特定の1つの具体型に固定される)
func makeShape() -> some Shape {
return Circle(radius: 5)
}
// any: 存在型(任意のプロトコル準拠型を格納できる)
var shapes: [any Shape] = [Circle(radius: 5), Rectangle(width: 3, height: 4)]
// プライマリ関連型(Swift 5.7+)
func process(_ values: some Collection<Int>) { }
構文一覧
| 構文 | 概要 |
|---|---|
| some プロトコル | 不透明型。コンパイラが具体型を知っているが呼び出し側には隠す。戻り値型や引数型に使います。 |
| any プロトコル | 存在型。任意のプロトコル準拠型を格納できる。異なる型を配列に混在させる場合に使います。 |
| some Collection<T> | プライマリ関連型構文。Collection の要素が T であることを指定します。 |
サンプルコード
// プロトコルの定義
protocol Animal {
var name: String { get }
func sound() -> String
}
struct Dog: Animal {
let name: String
func sound() -> String { return "ワン" }
}
struct Cat: Animal {
let name: String
func sound() -> String { return "ニャン" }
}
// some: 戻り値が1つの固定した具体型(呼び出し側は知らない)
func makeDog() -> some Animal {
return Dog(name: "ポチ")
}
let dog = makeDog()
print("\(dog.name): \(dog.sound())")
// any: 異なる具体型を同じ型として扱える存在型
let animals: [any Animal] = [
Dog(name: "ポチ"),
Cat(name: "タマ"),
Dog(name: "コロ")
]
for animal in animals {
print("\(animal.name): \(animal.sound())")
}
// some と any の違い
// some: 関数が常に同じ具体型を返す(コンパイラが最適化できる)
// any: 任意の型を格納できる(ボックス化によるオーバーヘッドあり)
// Swift 5.7+ のプライマリ関連型構文
func sumAll(_ numbers: some Collection<Int>) -> Int {
return numbers.reduce(0, +)
}
print("合計: \(sumAll([1, 2, 3, 4, 5]))")
print("合計: \(sumAll(Set([10, 20, 30])))")
概要
『some』は「呼び出し側には型を隠すが、コンパイラは具体型を知っている」不透明型です。関数が常に同じ具体型を返す場合に使い、パフォーマンスが良好です。SwiftUIの『body: some View』がこの典型例です。
『any』は「任意のプロトコル準拠型を格納できる」存在型です。異なる型を配列に混在させるなど、実行時に型が変わる場面で使います。Swift 5.7 以降では、プロトコルを型として使う際に any キーワードが必要になりました。some との混同に注意してください。
ジェネリック関数についてはジェネリック関数 / 型パラメータを参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。