1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Swiftのenumの使い方を学んでみた

Last updated at Posted at 2021-08-30

#この記事について

THE SWIFT PROGRAMMING LANGUAGE SWIFT5.5を参考・引用しております。

間違っていたら指摘お願いします。

enumの基礎編

書き方①

enumの基本的な書き方
enum CompassPoint { 
    case north
    case south
    case east
    case west
}

var directionToHead = CompassPoint.west 
directionToHead = .east

enum(列挙型)は、関連する値のグループに共通の型を定義し、コード内で型安全な方法でこれらの値を扱うことができます。

上記の例で言うと、
north,south,east,westの値をCompassPointという任意の共通の型で定義し、グループ化しています。

それにより、
CompassPoint.westという書き方ができるようになります。

私は、「CompassPointグループのwest君」みたいな覚え方をしております。

var directionToHead = CompassPoint.west
変数にenumで定義した型の値を代入すると、変数はその型を覚えてくれます。

directionToHead = .east
それにより、次に同じ型の値を代入する際は、省略した書き方をすることができます。

書き方②

1つのcaseに複数の値を設定した書き方
enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune //1行で表示もできる
}

「enumの書き方①」では、1つのcaseに1つの値を設定していましたが、実は1つのcaseに複数の値を設定することができます。

enumの応用篇

switchとenumで値をマッチングさせる

switchとeunmを使用した書き方
directionToHead = .south

switch directionToHead { 
case .north:
    print("Lots of planets have a north")
case .south:
    print("Watch out for penguins")
case .east:
    print("Where the sun rises")
case .west:
    print("Where the skies are blue")
default:
    print("Not a safe place for humans")
}

switchとenumを組み合わせることで、enumの値に合わせて処理を実行することができます。

値がない場合は、default内の処理が実行されます。

enumにCaseIterableプロトコルを実装し、値をプロパティーとして扱う

enumとプロトコルを使用した書き方
enum Beverage: CaseIterable { 
    case coffee,tea,juice
}

let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) beverages available")

for beverage in Beverage.allCases {
    print(beverage)
}

上記では、enumにCaseIterableプロトコルを実装させ、caseの値をプロパティーとして扱えるようにしています。

プロパティーと扱えることにより、
allCases.countでcaseの数を数えたり、
for beverage in Beverage.allCasesで、caseの値をループで出力できるようになります。

enumに代入した値を再利用


enum Barcode {
    case upc(Int,Int,Int,Int)
    case qrCode(String)
}

var productBarcode = Barcode.upc(8, 85909,51226,3)

switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
    print("QR code: \(productCode).")
}

case upc(Int,Int,Int,Int)
case qrCode(String)
enumのcaseでは上記の書き方ができます。
これは、各caseの値の型を定義しております。

「Barcodeグループのupc君がint型の値を4つ保持できる」と覚えると良いでしょう

var productBarcode = Barcode.upc(8, 85909,51226,3)
上記のように値を代入することができます。

enum、定義済みのcase、switchを使うことで、
enumに代入した値をswitchのcaseの処理内で再利用することができます。

enum応用篇②

生の値を定義

生の値を定義する

//明示的に生の値を定義する
enum ASCIIControlCharcter: Character { 
    case tab = "\t"
    case lineFeed = "\n"
    case carriageReturn = "\r"
}

//暗黙的に生の値を定義する
enum PlanetA: Int {
    case mercury = 1, venus, earth, mars,jupiter,saturn,uranus, neptune 
//venusは2になる。
//earthは3になる
}

ややこしいですが、enum(列挙型)は、関連する値のグループに共通の型を定義する以外にも他のことができます。

それは、「生の値」を定義することです。

上記の例だとCharacter型を使って
値にtabを、
生の値に"\t"を定義しています。

Int型を使えば、暗黙的に生の値を定義することができます。

「生の値」を定義する際には、他のcaseの生の値も全て同じ型である必要があります。

生の値から値を引っ張り出し、マッチング
let positionToFind = 11
if let somePlanet = PlanetA(rawValue: positionToFind) { //オプショナルを外している
    switch somePlanet {
    case .earth:
        print("Mostly harmless")
    default:
        print("Not a safe place for humans")
    }
} else {
    print("There isn't a planet at position \(positionToFind)")
}

値と生の値の関係性について、
連想配列のキーと値の関係性に似ているような感じがします。

rawValueで生の値を定義することで、値を引っ張り出すことができます。ただし、オプショナル型なのでif letなどでアンラップする必要があります。

再帰的なenum

indirectでcaseが再帰的であると明示する
enum ArithmeticExpression {
    case number(Int)
    indirect case addtion(ArithmeticExpression,ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression,ArithmeticExpression)
}

再帰的な列挙(enum)とは、1つ以上の列挙ケースの関連する値として、その列挙の別のインスタンスを持つ列挙のことです。列挙ケースの前に indirect と書くことで、再帰的であることを示し、コンパイラに必要なインダイレクトの層を挿入するように指示します。

すべてのcaseが再帰的であると明示する
indirect enum ArithmeticExpressionA {
    case number(Int)//普通の数字
    case addition(ArithmeticExpressionA, ArithmeticExpressionA) //加算
    case multiplication(ArithmeticExpressionA, ArithmeticExpressionA) //乗算
}

enumの前にindirectを書くことで、すべてのcaseが再帰的であると明示することができます。

再帰的なenumの使用例
//ArithmeticExpressionAの値を再帰的に利用する
let five = ArithmeticExpressionA.number(5)
let four = ArithmeticExpressionA.number(4)
let sum = ArithmeticExpressionA.addition(five, four) 
let product = ArithmeticExpressionA.multiplication(sum, ArithmeticExpressionA.number(2))

// switchで値をアンラップする
func evaluate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    case let .number(value):
        return value
    case let .addition(left, right):
        return evaluate(left) + evaluate(right)
    case let .multiplication(left, right):
        return evaluate(left) * evaluate(right)
    }
}
print(evaluate(product))
// Prints "18"

上記の処理だと、
変数sumが同じenumであるfivefourを持っています。
さらに、変数productは、同じenumであるsumArithmeticExpressionA.number(2)を持っています。

このように、enumが同じenumを持つことを再帰的なenumと呼ばれています。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?