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


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.