2
1

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.

列挙型を活用して返り値の?を外す

Last updated at Posted at 2021-05-23

導入

以下のような問題を想定します。

func randomDirection() -> String{
    ["前","右","後","左"].randomElement()!
}

と定義されたrandomDirectionを引数として、前であれば右、右であれば後といったように時計回りの方向を文字列で返す関数を作成せよ。

考察

🤔「switch使ったろ!」

func nextDirection(direction: String) -> String {
    switch direction {
    case "前":
        return "右"
    case "右":
        return "後"
    case "後":
        return "左"
    case "左":
        return "前"
    }
}

👮‍♂️「Switch must be exhaustive(網羅できてないよ)」

😅「」

😁「せや!case "左"をdefaultとして扱ったろ!」

func nextDirection() -> String {
    switch randomDirection() {
    case "前":
        return "右"
    case "右":
        return "後"
    case "後":
        return "左"
    default:
        return "前"
    }
}

🕵️‍♂️「値を取得する関数がrandomDirection()のように簡単な関数であるとは限りません。それ以外の場合と一つの値を同じ処理にしてしまうのはバグの発見を遅らせてしまうため、いい実装とは言えません。」

😭「」

😁「せや!defaultの時はnilとしたろ!」

func nextDirection(direction: String) -> String {
    switch direction {
     case "前":
        return "右"
    case "右":
        return "後"
    case "後":
        return "左"
    default:
        return "前"
    default:
        return nil
    }
}

👮‍♂️「'nil' is incompatible with return type 'String'(返り値はStringなんだがw)」

😁「返り値String?にしたろ!」

🕵️‍♂️「問題はStringで返す関数を作成することです。」

😭「『switchの分岐を全て網羅すること』と『型にオプショナルを加えないこと』とが両立できない」

列挙型(enum)を使う

🕵️‍♂️「列挙型を使うといいよ」

🧐「なるほど」

enum Direction {
    case 
    case 
    case 
    case 
}

🧐「とすればDirection型は4つのどれかであるといえるのか。これらは変数の名前だから値を持たせる必要があるな。」

enum Direction: String {
    case  = "前"
    case  = "右"
    case  = "後"
    case  = "左"
}

🧐「rawValueを使えば値から型を作れるのか」

let direction = Direction(rawValue: direction)!

😁「これを使って関数を書き換えられる!」

func nextDirection(direction: String) -> String {
    let direction = Direction(rawValue: direction)!
    switch direction {
    case .:
        return "右"
    case .:
        return "後"
    case .:
        return "左"
    case .:
        return "前"
    }
}

👮‍♂️「」

省略する

🕵️‍♂️「caseとvalueが一致してたら省略できます。」

enum Direction: String {
    case 
    case 
    case 
    case 
}

😍「すごい」

工夫する

🕵️‍♂️「CaseIterableを使えば列挙型の全てを取得するallCasesが使えます。」

enum Direction: String, CaseIterable {
    case 
    case 
    case 
    case 
}

🤔「配列いじればswitch自体使わなくても実装できそうだな。」

func nextDirection(direction: String) -> String {
    let allcases = Direction.allCases
    let direction = Direction(rawValue: direction)!
    let index = allcases.firstIndex(of: direction)!
    if index == allcases.count-1 {
        return allcases[0].rawValue
    }else {
        return allcases[index+1].rawValue
    }
}

😍「かっこいい」

🤔「けどもうここまできたら関数をいじるんじゃなくて列挙型の中身をいじった方が良くないか?」

enum Direction: String {
    case 
    case 
    case 
    case 
    var next: String {
        switch self {
        case .:
            return "右" 
        case .:
            return "後"
        case .:
            return "左"
        case .:
            return "前"
        }
    }
}

🤔「こんな感じになるな」

func nextDirection(direction: String) -> String {
    let direction = Direction(rawValue: direction)!
    return direction.next
}

😁「良い感じ!列挙型って便利!」

終わり

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?