Быстрая мутирующая функция как первоклассное значение
У меня может быть функция, чтобы поменять местами первые два элемента массива:
func swapFirstTwo(array: inout [Int]) {
if array.count >= 2 {
array.swapAt(0, 1)
}
}
typealias Swapper = (inout [Int]) -> ()
// And I can have a variable = the function
let swapThem: Swapper = swapFirstTwo
// And it works like this:
var array = [1,2,3]
print(array)
swapThem(&array)
print(array)
// But I'm allergic to Global functions!
// It would be more swifty to have:
extension Array where Element == Int {
mutating func swapFirstTwo2() {
if count >= 2 {
swapAt(0, 1)
}
}
}
typealias Swapper2 = (inout [Int]) -> () -> ()
// But when I do this:
let swapThemAgain: Swapper2 = Array.swapFirstTwo2
// I get the error:
// Partial application of 'mutating' method is not allowed; calling the function has undefined behavior and will be an error in future Swift versions
var array2 = [1,2,3]
print(array2)
array2.swapFirstTwo2()
print(array2)
// This in fact works but I've tried similar things and sometimes they appear to be unstable.
// How can I achieve doing: array2.swapFirstTwo2() without getting the error?
Это на самом деле работает, но я пробовал похожие вещи, и иногда они кажутся нестабильными. Также необходимо учитывать предупреждение компилятора. Как я могу добиться выполнения: array2.swapFirstTwo2() без получения предупреждения / ошибки?
1 ответ
Причина, по которой вы получаете предупреждение (и вскоре будет ошибка в режиме Swift 5):
extension Array where Element == Int {
mutating func swapFirstTwo2() {
if count >= 2 {
swapAt(0, 1)
}
}
}
typealias Swapper2 = (inout [Int]) -> () -> ()
let swapThemAgain: Swapper2 = Array.swapFirstTwo2
связано с тем, что inout
Аргументы действительны только на время вызова, которому они передаются, и поэтому не могут быть применены частично.
Так что, если вы должны были позвонить возвращенным (inout [Int]) -> () -> ()
с &array2
, вы бы вернулись () -> ()
который теперь имеет недопустимую ссылку на array2
, Попытка вызова этой функции приведет к неопределенному поведению, так как вы пытаетесь изменить inout
аргумент за пределами окна, где он действителен.
Эта проблема будет исправлена, если / когда не примененные методы экземпляра получат плоские подписи, как Array.swapFirstTwo2
вместо этого будет оценивать (inout [Int]) -> ()
,
Но в то же время вы можете обойти проблему, используя вместо этого замыкание:
typealias Swapper2 = (inout [Int]) -> ()
let swapThemAgain: Swapper2 = { $0.swapFirstTwo2() }
var array2 = [1,2,3]
print(array2) // [1, 2, 3]
array2.swapFirstTwo2()
print(array2) // [2, 1, 3]