Швидкий зробити параметр методу змінним?


123

Як я можу впоратися з цією помилкою без створення додаткової змінної?

func reduceToZero(x:Int) -> Int {
    while (x != 0) {
        x = x-1            // ERROR: cannot assign to 'let' value 'x'
    }
    return x
}

Я не хочу створювати додаткову змінну просто для збереження значення x. Чи можливо навіть робити те, що я хочу?


3
Дивіться оновлені відповіді нижче, Swift 3 застарівши вашу прийняту відповідь.
— ачі

Відповіді:


192

Як зазначено в інших відповідях, станом на Swift 3 розміщення var перед тим, як змінна була знята. Хоча це не зазначено в інших відповідях, це можливість оголошення inoutпараметра. Подумайте: проходження вказівника.

func reduceToZero(_ x: inout Int) {
    while (x != 0) {
        x = x-1     
    }
}

var a = 3
reduceToZero(&a)
print(a) // will print '0'

Це може бути особливо корисно при рекурсії.

inoutНастанови Apple щодо декларацій можна знайти тут .


2
Велике спасибі!!!! Я застряг тут на запитанні рекурсії. Ти врятував мені життя.
— JW.ZG

2
Слід використовувати це з обережністю, оскільки це змінює змінні за межами області функцій. В ідеалі ви хочете явно повернути значення, яке ви змінили всередині функції.
— Кріс Гунавардена

2
inoutКлючове слово має бути розміщено між назвою параметра та типом параметра таким чином: func reduceToZero(x: inout Int) у поточній версії Swift 3.
— Август Санчес

За винятком цього, здається, не працює для закриттів, оскільки закриття, очевидно, фіксують лише параметри входу за значенням (принаймні, це повідомлення про помилку, яке мені дає Xcode). Я використовую рішення @GeRyCh в цьому випадку.
— wcochran

Дякую. Це працювало наразі, але начебто за допомогою покажчиків у C. Чи пережив би це ще одну версію Swift?
— Кришна Ведула

45

Параметри 'var' застаріли і будуть видалені у Swift 3. Тому призначення нового параметра здається найкращим способом:

func reduceToZero(x:Int) -> Int {
    var x = x
    while (x != 0) {
        x = x-1            
    }
    return x
}

як згадувалося тут: параметри 'var' застаріли і будуть видалені у Swift 3


1
У цьому випадку це насправді копіює xнове var x? Або Свіфт робить щось більш ефективне?
— Генкі

3
Це працює і є те, що я роблю, але це здається дуже незручним.
— wcochran

1
@Gomfucius У посібнику Swift 3.1 про це не йдеться. У цьому випадку ( xвписується в реєстр) витрат практично немає. Якщо xмутація масиву, структури чи об'єкта, то майже напевно потрібно виконати копію (якщо оптимізатор не зможе проаналізувати її вбудованим чи псевдонімом).
— wcochran

1
@wcochran Це акуратний трюк, але насправді нічого особливого не відбувається. Це просто затемнення вхідного параметра з локальною копією var. У ситуації з ОП це краща заміна varаргументів, ніж використання, inoutяке може мати небажані побічні ефекти, особливо. якщо вар був вказівником.
— Ешелон

45

Для Swift 1 і 2 (для Swift 3 див. Відповідь achi, використовуючи параметр inout): Аргумент функції в Swift letза замовчуванням, тому змініть його на, varякщо вам потрібно змінити значення, тобто

func reduceToZero(var x:Int) -> Int {
    while (x != 0) {
        x = x-1     
    }
    return x
}

2
Чому ця відповідь підкреслена як пекло? Інша відповідь була розміщена перед цією і містить більше інформації, ніж ця.
— Крістік

16
/! \ Використання var створить копію змінної, переданої в параметрах. Таким чином, змінивши його, ви не зміните початкове значення. Також varу параметрах дуже ймовірно зникнути в нових версіях Swift per github.com/apple/swift-evolution/blob/master/proposals/…
— Matthieu Riegler

17
Ключове слово var у методі paremeter буде застарілим у Swift 3.
— Boon

4
Я думаю, що зі Swift 3 ми вже не зможемо цього зробити. Нам доведеться створити змінну копію масиву і повернути цей модифікований масив.
— C0D3

Ця відповідь є правильною відповіддю: stackoverflow.com/questions/24077880/…
— ачі

14

Відповідь Swift3 для передачі змінного вказівника масиву.

Функція:

func foo(array: inout Array<Int>) {
    array.append(1)
}

Дзвінок для функціонування:

var a = Array<Int>()
foo(array:&a)

Чесно кажучи, я не впевнений, чи правильно це, оскільки земля Свіфта постійно змінюється. Я думав, що це краще, ніж робити var array = масив всередині функції, тому що це робить копію (і насправді не впливає на оригінальну структуру масиву)? Чи є кращим дизайнерським підходом до вищезгаданого підходу var, а потім повернути новий мутований масив?
— joshd

7

У Swift ви просто додаєте varключове слово перед назвою змінної у декларації функції:

func reduceToZero(var x:Int) -> Int { // notice the "var" keyword
    while (x != 0) {
        x = x-1            
    }
    return x
}

Зверніться до підрозділу "Параметри постійного і змінного" у розділі "Функції" книги Swift (стор. 210 iBook, як це є сьогодні).


7
Параметри 'var' застаріли і будуть видалені в Swift 3
— Regis St-Gelais

1
Неправильно для Swift 4 та новіших версій.
— ilkayaktas

0

Є деякі випадки, коли ми не використовуємо inout

Ми можемо використовувати щось подібне, якщо ви хочете, щоб зміни / сфера застосування були лише всередині функції:

func manipulateData(a: Int) -> Int {
    var a = a
    // ...
}

0

Рішення за допомогою Swift5 з функціональним програмуванням ...

func reduceToZeroFP(x:Int) -> Int {
    x == 0 ? x : reduceToZeroFP(x: x - 1)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.