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 подхода, о которых я могу думать:
- Передайте замыкание мутатора в метод decider, который выдает соответствующий var, чтобы мутировать как
inout
Param, а затем имеет закрытие тела мутировать его. Определите протокол, содержащий эти переменные (которые, как вы сказали, являются общими для нескольких типов), приведите эти типы в соответствие с ним и предоставьте расширение протокола, определяющее метод, который будет применяться ко всем из них. Этот подход я бы использовал даже в 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>
?