Inout + variadic parameters

swift

#1

Есть суперкласс, в котором реализован метод оптимизации параметров у наследуемых классов. Метод принимает переменные и массив для возможных значений, далее перебирает все возможные комбинации из переменных и возможных значений и создает большой массив, затем идет цикл: устанавливается значение для каждого параметра и уже проверка этих параметров.

class SuperClass {
//…
final func optimize(pars: inout (Any, [Any])…) {
//…
}
}

class InheritedClass1: SuperClass {
var par1: Int
var par2: Bool
//…
}

class InheritedClass2: SuperClass {
var par1: Double
var par2: Int
var par3: Int
//…
}

inheritedClass1 = InheritedClass1()
inheritedClass1.optimize(pars: (inheritedClass1.par1, Array(stride(from: 18, through: 28, by: 1))), (inheritedClass1.par2, [true, false]))

У наследуемых классов может быть любое кол-во параметров и разные типы. Значения для оптимизации par1 можно установить например вот так: Array(stride(from: 18, through: 28, by: 1)), для par2 просто [true, false]

Столкнулся с проблемой - inout не работает для variadic параметрами. Как это все лучше реализовать в таком случае?


#2

Покажите реализацию метода optimize(pars:) так не совсем понятно что это и зачем.


#3

Да, наверное сейчас должно быть понятнее. В суперклассе:

private func combinations<T>(of array: [[T]]) -> [[T]] {
    return array.reduce([[]]) {
        var tmp = [[T]]()
        for i in $0 {
            for j in $1 {
                tmp.append(i + [j])
            }
        }
        return tmp
    }
}

final func optimize(parameters: (Any, [Any])...) {
    //parameters: [Any], values: [[Any]]
    
    let optimizationList = combinations(of: parameters.map { $0.1 })
    
    for i in 0 ..< optimizationList.count {
        for j in 0 ..< parameters.count {
            parameters[j].0 = optimizationList[i][j] // <--
        }
        check()
    }
}

То есть необходимо установить значения для внешних переменных. Если бы их кол-во было заранее известно, то было бы все просто - inout.


#4

Зачем вам тогда суперкласс если переменные передаёте из вне?

И что это за оптимизация такая, если всегда присваивается последнее значение из массива?

Еще не известно что делает check() может в нём вся тайна :slight_smile:

Можете попробовать так:

prefix operator &!

prefix func &!<T>(value: inout T) -> UnsafeMutablePointer<T> {
    return {$0}(&value)
}

class SuperClass {
    
    private func combinations<T>(of array: [[T]]) -> [[T]] {
        return array.reduce([[]]) {
            var tmp = [[T]]()
            for i in $0 {
                for j in $1 {
                    tmp.append(i + [j])
                }
            }
            return tmp
        }
    }
    
    final func optimize(parameters: (Any, [Any])...) {
        let optimizationList = combinations(of: parameters.map { $0.1 })
        
        for i in 0..<optimizationList.count {
            for j in 0..<parameters.count {
                switch (parameters[j].0, optimizationList[i][j]) {
                case (let pointer as UnsafeMutablePointer<Int>, let value as Int): pointer.pointee = value
                case (let pointer as UnsafeMutablePointer<Double>, let value as Double): pointer.pointee = value
                case (let pointer as UnsafeMutablePointer<Bool>, let value as Bool): pointer.pointee = value
                default: break
                }
            }
        }
    }
}

class InheritedClass1: SuperClass {
    var par1: Int = 0
    var par2: Bool = false
    var par3: Double = 0
}

let inheritedClass1 = InheritedClass1()
inheritedClass1.optimize(parameters: (&!inheritedClass1.par1, Array(stride(from: 18, through: 28, by: 1))), (&!inheritedClass1.par2, [false, true]), (&!inheritedClass1.par3, [10.2, 11.6, 15.9]))

print(inheritedClass1.par1)
print(inheritedClass1.par2)
print(inheritedClass1.par3)

Но гораздо проще если у вас будет какой-то такой метод:

func optimize<T>(params: [T]) -> T {
    // ...
}

И использовать его так:

let inheritedClass1 = InheritedClass1()
inheritedClass1.par1 = optimize(params: [1, 2])
inheritedClass1.par2 = optimize(params: [true, true])
inheritedClass1.par3 = optimize(params: [1.1, 2.2])

#5

В суперклассе идет общее описание, а все переменные, которые необходимо установить уже находятся наследуемых классах, и в каждом из них уже заложен свой алгоритм. И этот алгоритм идет в check() - как вы правильно предположили )) То есть идея заключается в том, чтобы присвоить значения переменным в методе optimize(), который реализован в суперклассе, а вызывать его из наследуемого, который запустит check() и проверит и оценит результаты работы алгоритма с этими значениями.

Еще не проверял в xcode, но кажется первый вариант, который вы предложили - это как раз то, что нужно! Во втором варианте вы исходите из того, что кол-во переменных равно трем, а оно в каждом наследуемом классе может отличаться. Буду пробовать. Спасибо!