简体   繁体   English

带有关联值的开关内部的快速突变

[英]Swift Mutation inside switch with associated values

I have these structs I want to mutate: 我有想要变异的这些结构:

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]
    }
}

I want to use this mutating func select() method inside SelectableArray, I am calling it from a chain of mutating functions (because Sections is nested inside a struct) 我想在SelectableArray中使用此变异func select()方法,我是从一系列变异函数中调用它的(因为Sections嵌套在struct中)

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
    }
}

The problem is that the CheckoutViewModel struct is never mutated. 问题是CheckoutViewModel结构永远不会发生突变。 I am guessing that switch is not a mutating function, so var modes inside that switch is non mutable and then it does not matter if the following functions mutate anything. 我猜想该开关不是一个可变函数,因此该开关内的var modes是不可变的,因此以下函数是否对任何东西都无所谓。 The workaround I managed to do is this: 我设法解决的方法是这样的:

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
    }
}

Do you have any oher solution to this problem? 您对此问题有其他解决方案吗? Is there any sort of mutating switch function that I can use? 我可以使用任何种类的mutating switch功能吗?

According to The Swift Programming Language : 根据Swift编程语言

A switch case can bind the value or values it matches to temporary constants or variables, for use in the body of the case. switch案例可以将其匹配的一个或多个值绑定到临时常量或变量,以用于案例主体中。 This behavior is known as value binding, because the values are bound to temporary constants or variables within the case's body. 此行为称为值绑定,因为值绑定到案例主体内的临时常量或变量。

Changes to such a temporary variable (eg the modes variable) do not affect the contents of the enum that is being switched on (eg kind ). 更改此类临时变量(例如, modes变量)不会影响正在打开的枚举的内容(例如, kind )。

For your first approach to work you would indeed need a different sort of switch statement that creates a reference to the enum's associated value, allowing you to modify that value in place. 对于第一种工作方法,确实确实需要另一种switch语句,该语句创建对枚举的关联值的引用,从而允许您就地修改该值。 Such a statement doesn't exist in Swift 3.0.1. 这样的声明在Swift 3.0.1中不存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM