Mutating func с внешним определением, какую переменную нужно изменить

У меня есть структура с 2 переменными. Эта структура имеет мутирующую функцию, но в этой функции мне нужно проверить, какую переменную мутировать. Для этого я использую статическую функцию отдельного класса со сложной логикой. Этот класс работает с различными структурами, поэтому для СУХОЙ цели я не могу представить эту логику во всех этих структурах.

Проблема в том, что я не знаю, как получить переменную той же структуры из этого отдельного класса, поэтому никакие переменные структуры не являются мутированными. Я думаю, что я скучаю по некоторым знаниям Swift, потому что я уверен, что это возможно, не дублируя логику.

Код для представления его на игровой площадке:

struct SomeStruct {
    var a = "a"
    var b = "b"

    mutating func mutateString(to newString: String) {
        var varToMutate = VariableDetector.whichVarToMutate(a, b)
        varToMutate = newString

        // prints to represent question
        print("varToMutate: \(varToMutate)")
        print("a: \(a)")
        print("b: \(b)")
    }
}

class VariableDetector {
    static func whichVarToMutate(_ first: String, _ second: String) -> String {
        var firstOrSecondString = ""

        // simple logic to represent question, in real case it is far more complex
        if first == "a" {
            firstOrSecondString = first
        } else {
            firstOrSecondString = second
        }

        return firstOrSecondString
    }
}

var someStruct = SomeStruct()
someStruct.mutateString(to: "c")

Этот код производит:

varToMutate: c
a: a
b: b

Да, это можно решить с помощью:

if varToMutate == a {
    a = newString
} else if varToMutate == b {
    b = newString
}

Но я хочу решить это более элегантно:)

Спасибо за любую помощь!

2 ответа

Решение

В Swift 4 это можно сделать, вернув KeyPath от whichVarToMutate, KeyPath затем может быть использован для доступа к рассматриваемому экземпляру и изменения свойства, которое он представляет.

В Swift 3 есть 2 подхода, о которых я могу думать:

  1. Передайте замыкание мутатора в метод decider, который выдает соответствующий var, чтобы мутировать как inout Param, а затем имеет закрытие тела мутировать его.
  2. Определите протокол, содержащий эти переменные (которые, как вы сказали, являются общими для нескольких типов), приведите эти типы в соответствие с ним и предоставьте расширение протокола, определяющее метод, который будет применяться ко всем из них. Этот подход я бы использовал даже в Swift 4:

    struct SomeStruct {
        var a = "a"
        var b = "b"
    }
    
    protocol Mutable { // TODO: Rename me appropriately
        var a: String { get set }
        var b: String { get set }
    }
    
    extension SomeStruct: Mutable {}
    
    extension Mutable {
        mutating func changeAppropriateVar(to newValue: String) -> Void {
            // simple logic to represent question, in real case it is far more complex
            let someCondition = true
    
            if someCondition {
                print("Setting `a` to \(newValue)")
                a = newValue
            }
            else {
                print("Setting `b` to \(newValue)")
                b = newValue
            }
        }
    }
    
    var s = SomeStruct()
    s.changeAppropriateVar(to: "foo")
    

Если не a а также b экземпляры класса, ваш varToMutate будет только копией, потому что все, кроме Class, является типом значения в Swift. Может быть попробовать UnsafeMutablePointer<T>?

Другие вопросы по тегам