SwiftでC言語のunion
的な使い方
先日勉強会でSwiftにはC言語の共用体union
ってないのでしょうかという質問があったので、Swiftでunion
的な使い方を紹介したいと思います。
enum
をC言語の共用体として使う
Swiftの予約後にはunion
keywordはありません。Swift のドキュメント*1 にはバーコードの値を扱うenum Barcode
の例が出ています。UPCA
とQRCode
では扱うデータの型が異なるため同じ型として扱いにくいのは確かですが、Swiftのenum
を使えば、union
のように扱う事ができます。
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
UPCA
とQRCode
では異なるデータの型を扱いたいので、それぞれのキーワードの後に括弧で扱いたい型を指定すれば良いです。これを Associated Value と言います。
let barcode1 = Barcode.UPCA(8, 85909, 51226, 3)
let barcode2 = Barcode.QRCode("Hello World")
こうなれば、UPCAもQRCodeも一つの型として扱いやすいので、Any
じゃなくても配列として扱える。
let barcodes: [Barcode] = [barcode1, barcode2]
Associated Value を取り出す
では、Barcode
の値を引き渡された関数を想定して、その値をprint
してみましょう。Optional
型がUnwarpしないと値が取り出せないように、enum
のassociated valueも値を取り出すような一手間が必要になります。case
節の中のlet
やvar
で値を取り出します。
func process(barcode: Barcode) {
switch barcode {
case .UPCA(let a, let b, let c, let d):
print("UPCA: \(a),\(b),\(c),\(d)")
case .QRCode(let string):
print("QR: \(string)")
}
}
もちろん値を取り出す必要がない場合は括弧全体を省略できます。
case .UPCA: print("UPCA")
case .QRCode: print("QRCode")
一つの型のみ注力して値を取り出したい場合は、まぁswitch
文を使ってもいいのですが、if 文でも書く事が出来ます。if let
といった書き方とずいぶん雰囲気が変わるので、面食らうかもしれませんが、慣れると簡潔にかけていいかもしれません。
if case .QRCode(let string) = barcode {
print("\(string)")
}
ちょっと一工夫でより便利に
こうした associated valueの取り出すコードを何度も繰り返さなければいけない場合が予想される場合は、enumの型自体に、メソッドなどを用意すると便利になる場合があります。
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
var UPCA: (Int, Int, Int, Int)? {
if case .UPCA(let a, let b, let c, let d) = self {
return (a, b, c, d)
}
return nil
}
var QRCode: String? {
if case .QRCode(let string) = self {
return string
}
return nil
}
}
if let code = barcode.QRCode {
print("\code")
}
JSONの要素などの表現
このようにenum
を使えば、JSONの要素のように、値の型がはっきりしない要素を扱う事が容易になります。この場合Null
には associated value は必要ありませんね。
enum Element {
case String(Swift.String)
case Boolean(Bool)
case Integer(Int)
case Float(Swift.Float)
case Dictionary([Swift.String: Element])
case Array([Element])
case Null
}
Swift.String
や Swift.Float
は ネームスペースの問題で Swift
がついていますが、今回は割愛させていただきます。
*1 The Swift Programming Language (Swift 2 Prerelease)