Как написать функцию мутации для enum в Swift - PullRequest
0 голосов
/ 16 июня 2020

Я хочу написать функцию изменения, подобную следующей. Но этот код не может быть скомпилирован, потому что x и y являются неизменяемыми и копируемыми значениями. Я хочу получить ссылку на x и y. Как получить ссылку на переменные, обернутые enum?

enum Fruit {
    case apple(Int)
    case banana(Int, Int, Int)

    mutating func increment() {
        switch self {
        case let .apple(x):
            x += 1
        case let .banana(x, y, z):
            x += 1
        }
    }
}

var a = Fruit.banana(100, 200, 300)
a.increment()

Я знаю, что следующий код может сделать то же самое. Но я думаю, что это решение излишне, потому что мы должны писать каждую переменную дважды.

enum Fruit {
    case apple(Int)
    case banana(Int, Int, Int)

    mutating func increment() {
        switch self {
        case let .apple(x):
            self = .apple(x + 1)
        case let .banana(x, y, z):
            self = .banana(x + 1, y, z)
        }
    }
}

var a = Fruit.banana(100, 200, 300)
a.increment()

1 Ответ

0 голосов
/ 07 июля 2020

Использование self = .apple(x) сделает свое дело. Это принято, но вы это уже знали.

enum Fruit {
    case apple(Int)
    case banana(Int, Int, Int)

    mutating func increment() {
        switch self {
        case let .apple(x):
            self = .apple(x + 1)
        case let .banana(x, y, z):
            self = .banana(x + 1, y + 1, z + 1)
        }
    }
}

var a = Fruit.banana(100, 200, 300)
a.increment()

Вы также можете добавить поддержку операторов generi c:

enum Fruit {
    case apple(Int)
    case banana(Int, Int, Int)

    mutating func operate(_ op: (Int, Int) -> Int,_ num: Int) {
        switch self {
        case let .apple(x):
            self = .apple(op(x, num))
        case let .banana(x, y, z):
            self = .banana(op(x, num), op(y, num), op(z, num))
        }
    }
}

var a = Fruit.banana(100, 200, 300)
a.operate(+, 1) // adds all by 1
a.operate(*, 500) // multiplies all by 500

Вы также можете добавить поддержку массива общих c операторов:

enum Fruit {
    case apple(Int)
    case banana(Int, Int, Int)

    mutating func operate(_ nest: [((Int, Int) -> Int, Int)]) {
        for i in nest {
            switch self {
            case let .apple(x):
                self = .apple(i.0(x, i.1))
            case let .banana(x, y, z):
                self = .banana(i.0(x, i.1), i.0(y, i.1), i.0(z, i.1))
            }
        }
    }
}

var a = Fruit.banana(100, 200, 300)
a.operate([(+, 500), (*, 2)]) // Adds all by 500, then multiply all by 2

Вот красивое упрощение

Если бы это было на мое усмотрение, это то, что я сделал бы, чтобы избавиться от повторения self =. Вы можете упростить это еще больше, если вы используете sh.

enum FruitList: String { case apple, banana }
struct Fruit {
    static func apple(_ one: Int) -> Fruit {
        return Fruit.init(.apple, [one])
    }
    static func banana(_ one: Int,_ two: Int,_ three: Int) -> Fruit {
        return Fruit.init(.apple, [one, two, three])
    }
    
    var picked: (FruitList, [Int])
    init(_ fruit: FruitList,_ list: [Int]) {
        picked = (fruit, list)
    }
    
    mutating func operate(_ nest: [((Int, Int) -> Int, Int)]) {
        for i in nest {
            for j in 0..<picked.1.count {
                picked.1[j] = i.0(picked.1[j], i.1)
            }
        }
    }
}


var a = Fruit.apple(100)
a.operate([(+, 500), (*, 2)]) // Add all by 500, then multiply all by 2
...