Swift 具有相关值的开关内部突变

Swift Mutation inside switch with associated values

我有这些我想改变的结构:

public struct CheckoutViewModel {
    var sections: [Section]
    var total: String

    public struct Section {
        var title: String
        var description: String
        var kind: Kind
        var expandState: ExpandState

        enum Kind {
            case products([ProductOrderViewModel])
            case shippingMode(SelectableArray<ShippingMode>)
            case shippingTarget(SelectableArray<ShippingKind>)
            case billingAddress(SelectableArray<Address>)
            case payment(SelectableArray<PaymentProvider>)
            case promoCode(String?)
            case legalAdvice(userAccepted: Bool)
        }
    }
}

struct SelectableArray<T> {
    var selectedIndex: Int?
    let options: [T]

    init(options: [T]) {
        self.options = options
        self.selectedIndex = nil
    }

    mutating func select(atIndex: Int) throws -> T {
        guard atIndex < options.count else {
            throw SelectableArrayError.outOfBoundsIndex
        }
        selectedIndex = atIndex
        return options[atIndex]
    }

    var selectedElement: T? {
        guard let selectedIndex = selectedIndex else { return nil }
        return options[selectedIndex]
    }
}

我想在 SelectableArray 中使用这个 mutating func select() 方法,我从一系列的 mutating 函数中调用它(因为 Sections 嵌套在一个结构中)

extension CheckoutViewModel {  
    mutating func select(atIndexPath indexPath: IndexPath) {
        sections[indexPath.section].select(atIndex: indexPath.row)
    }
}

extension CheckoutViewModel.Section {
    mutating func select(atIndex idx: Int) {
        switch kind {
            case .shippingMode(var modes):
                do { _ = try modes.select(atIndex: idx) } catch { return }
            default:
                return nil
        }
        dump(self) // Here self hasn't changed
    }
}

问题是 CheckoutViewModel 结构永远不会发生变化。我猜 switch 不是一个变异函数,所以那个 switch 里面的 var modes 是不可变的,那么下面的函数是否改变任何东西都没有关系。我设法做的解决方法是:

mutating func select(atIndex idx: Int) {
    switch kind {
    case .shippingMode(var modes):
        do {
            _ = try modes.select(atIndex: idx)
            self.kind = .shippingMode(modes)
        } catch { return }
    default:
        return
    }
}

对于这个问题,你有什么其他的解决办法吗?有什么我可以使用的 mutating switch 函数吗?

根据The Swift Programming Language

A switch case can bind the value or values it matches to temporary constants or variables, for use in the body of the case. This behavior is known as value binding, because the values are bound to temporary constants or variables within the case’s body.

更改此类临时变量(例如 modes 变量)不会影响正在打开的枚举的内容(例如 kind)。

对于第一种工作方法,您确实需要一种不同类型的 switch 语句来创建对枚举关联值的引用,从而允许您就地修改该值。 Swift 3.0.1.

中不存在这样的声明