Параметри 'var' застаріли і будуть видалені в Swift 3


120

Добре, тому я просто оновлюю Xcode до 7,3, і тепер я отримую це попередження:

Параметри 'var' застаріли і будуть видалені в Swift 3

Як це виправити, коли мені потрібно використовувати var у цій функції:

public func getQuestionList(var language: String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

6
Як щодоpublic func getQuestionList(inout language: String) -> NSArray
TotoroTotoro

2
Ні, це не підходяща заміна. ОП, мабуть, не хоче getQuestionмати ніяких побічних ефектів.
BallpointBen

5
Я, чесно кажучи, поняття не маю, чому вони навіть розглядають питання про усунення цього. Це була одна з особливостей, яка зробила швидку приголомшливою!
Danny Bravo

Ніколи не використовував його сам і не розумію суєти.
Майк Таверн

@MikeTaverne (пізній відповідь) Розглянемо наступну функцію: func foo(_ bar: int) { /*use bar*/ bar+=1; foo(bar); }. Це неможливо без змін. Вам або потрібно створити окремий var у межах функції та скопіювати значення, або позначити параметр як inout. Перший повільний, другий викликає невизначеність поведінки. Багато алгоритмів використовують подібну рекурсію.
кевін

Відповіді:


82

Ви намагалися призначити новий var

public func getQuestionList(language: String) -> NSArray {
    var lang = language
    if self.data.count > 0 {
        if (lang.isEmpty) {
            lang = "NL"
        }
        return self.data.objectForKey("questionList" + lang) as! NSArray
    }

    return NSArray()
}

11
Не дуже, що я думаю, що ОР хотіла
сірка

6
Я б зрозумів питання ОП так само, як і @garana. OP не використовує inout у своєму питанні, вони просто мутують наявну змінну локально .
Ерік Айя

11
Насправді це правильне рішення. Ознайомтесь із проблемою еволюції Swift, яка запропонувала цю зміну: github.com/apple/swift-evolution/blob/master/proposals/…
Скотт Томпсон,

8
@TimVermeulen Усі хочуть використовувати прогресивну мову. Apple може розвивати свою мову різними способами, не змінюючи синтаксис щомісяця. Як відомо, тонна онлайн-фрагменту документів та коду закінчується чи застаріла через Apple. Розробники повинні завітати на цей сайт, щоб не раз повторювати про допомогу з багатьма дурними питаннями. Синтаксис повинен бути міцним з самого початку, якщо Apple хоче, щоб більше розробників було добре в ньому.
TomSawyer

25
Використовуйте var language = language, якщо ви не хочете вводити інше ім'я змінної (що було головною перевагою параметра var в першу чергу imo)
Harris

102

Обговорення видалення Var з функціонального параметра повністю задокументовано в цій публікації на GitHub: Видалити параметри Var

У цьому документі ви побачите, що люди часто плутають varпараметри з inoutпараметрами. varПараметр просто означає , що параметр є змінним в контексті функції, в той час як з inoutпараметром значення параметра в точці повернення буде скопійовано з функції , і в контекст абонента.

Правильний спосіб вирішити цю проблему - видалити varз параметра і ввести локальну varзмінну. Скопіюйте значення параметра у верхній частині програми у цю змінну.


44
Я взагалі не розумію цієї зміни, чому потрібно було б написати інший рядок, щоб створити змінний локальний var, краще, ніж просто визначити параметр як var?
Росс Барбіш

Для мене ця зміна хороша тим, що вона сприймає ситуації, коли я мав би реалізувати локальну змінну, але я цього не зробив, тому що я взяв простий вихід і прийняв (старий) пропозицію Свіфта про введення параметру введення var
dawid

1
Я з цим @RossBarbish. Отже ... це видаляється, оскільки ледачі розробники не можуть розрізнити параметри inout та var? Pfff ...
Danny Bravo

1
Це здається жахливо непотрібним ... вони мали б зберегти обидва варіанти.
Оскар Гомес

1
Напевно, швидше декларував локальну змінну поверх верхнього параметра за лаштунками. Тепер ми повинні це зробити вручну. Жодних змін у продуктивності, але ми втратили зручність, щоб допомогти новачкам просту концепцію.
самолюб

62

Просто додайте цей один рядок на початку функції:

var language = language

а решта вашого коду може залишатися незмінною, наприклад:

public func getQuestionList(language: String) -> NSArray {
    var language = language
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

5
Найкраща відповідь на сьогоднішній день. Потрібно змінити лише один рядок.
BallpointBen

Але виглядає так неприродно @James
asyncwait

1
Я вважаю, що це найкраща відповідь, оскільки вона зберігає те саме ім’я. Як і в інших поширених мовах.
еоніст

1
@RiverSatya Чому б не просто використовувати параметр безпосередньо?
Деклан МакКенна

1
Дійсно дивовижна пропозиція. Ми реалізуємо це таким чином у Swiftify :)
Crulex

13

Дуже багато людей пропонують inoutпараметр, але це дійсно не те, для чого вони розроблені. Крім того, це не дозволяє викликати функцію з letпостійною, а також з літеральною рядком. Чому ви просто не додаєте до підпису функції значення за замовчуванням?

public func getQuestionList(language language: String = "NL") -> NSArray {
    if data.count > 0 {
        return data.objectForKey("questionList" + language) as! NSArray
    } else {
        return NSArray()
    }
}

Просто переконайтеся, що не дзвонити getQuestionListз порожньою рядком у випадку, якщо ви хочете мову за замовчуванням, а просто залиште параметр:

let list = getQuestionList() // uses the default "NL" language

3
Я також не розумію, чому всі стрибали на вхідному рішенні, коли OP на початку навіть не використовували це ...
Ерік Айя

1
Вони припускали, що var та inout зробили те саме.
ryantxr

2

Швидкий 4

public func getQuestionList(language: inout String) -> NSArray {
    if self.data.count > 0 {
        if (language.isEmpty) {
            language = "NL"
        }
        return self.data.objectForKey("questionList" + language) as! NSArray
    }

    return NSArray()
}

getQuestionList(language: &someString)

У деяких випадках, як я вже зазначив (із складнішими налаштуваннями, що включають масиви), створення нового властивості в методі та мутація цього властивості може не завжди працювати. Не кажучи вже про те, що ви захаращуєте метод замість того, щоб просто додавати inoutпараметр і &його аргумент, для чого і був створений цей синтаксис.



0

Я думаю, що відповіді @Harris та @garanda - найкращий підхід.

У будь-якому випадку у вашому випадку вар немає необхідності, ви можете:

public func getQuestionList(language: String) -> NSArray {
    if self.data.count > 0 {
        return self.data.objectForKey("questionList" + (language.isEmpty ? "NL" : language)) as! NSArray
    }
    return NSArray()
}

0

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html

Параметри введення

Параметри функції за замовчуванням є константами. Спроба змінити значення параметра параметра зсередини тіла цієї функції призводить до помилки часу компіляції. Це означає, що ви не можете змінити значення параметра помилково. Якщо ви хочете, щоб функція змінила значення параметра, і ви хочете, щоб ці зміни зберігалися після завершення виклику функції, визначте цей параметр як параметр входу.

Ви вводите параметр входу, розміщуючи ключове слово inout безпосередньо перед типом параметра. Параметр вводу має значення, яке передається функції, модифікується функцією і передається назад із функції заміни вихідного значення. Для детального обговорення поведінки параметрів вхідних даних та пов'язаних з ними оптимізацій компілятора див. Параметри вводу.

Ви можете передати змінну лише як аргумент для параметра входу. Ви не можете передавати постійне або буквальне значення в якості аргументу, оскільки константи і літерали не можуть бути змінені. Ви розміщуєте ampersand (&) безпосередньо перед ім'ям змінної, коли передаєте її як аргумент параметру входу, щоб вказати, що вона може бути змінена функцією.

ПРИМІТКА

Параметри входу не можуть мати значення за замовчуванням, а різні параметри не можуть бути позначені як inout.

Ось приклад функції під назвою swapTwoInts ( : :), яка має два цілих цілих параметри під назвою a і b:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

Функція swapTwoInts ( : :) просто замінює значення b на a, а значення a на b. Функція виконує цю заміну, зберігаючи значення a у тимчасовій постійній, званій тимчасовійA, присвоюючи значення b до a, а потім призначаючи тимчасовеA b.

Ви можете викликати функцію swapTwoInts ( : :) з двома змінними типу Int, щоб поміняти свої значення. Зауважте, що імена someInt та anotherInt мають префікс із символом ampersand, коли вони передаються функції swapTwoInts ( : :)

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"

Наведений вище приклад показує, що вихідні значення someInt та anotherInt змінюються функцією swapTwoInts ( : :), хоча вони спочатку були визначені поза функцією.

ПРИМІТКА

Параметри вхідного виходу не збігаються з поверненням значення функції. Приклад swapTwoInts, наведений вище, не визначає тип повернення або повертає значення, але він все ще змінює значення someInt та anotherInt. Параметри вводу-виходу є альтернативним способом для того, щоб функція мала вплив за межі сфери її функції.


0

Ось ще одна ідея. Моє використання полягало в тому, щоб пройти навколо рядкового масиву, щоб додати його, для чого масив повинен бути переданий без змін. Я теж не хотів мати штат у своєму класі для цього. Тому я зробив клас, який містить масив і передав його. Залежно від випадку використання, може здатися, що клас може містити саме цю змінну.

private class StringBuilder {
    var buffer: [String] = []

    func append(_ str: String) {
        buffer.append(str)
    }

    func toString() -> String {
        return buffer.joined()
    }
}

Я використовую лише методи appendта joinedметоди в масиві, так що було легко змінити тип з мінімальними іншими змінами до мого коду.

Деякі приклади використання:

private func writeMap(map: LevelMap, url: URL) -> Bool {
    let buffer = StringBuilder()

    if !writeHeader(map: map, buffer: buffer) {
        return false
    }
    if !writeFloors(map: map, buffer: buffer) {
        return false
    }

    let content = buffer.toString()
    do {
        try content.write(to: url, atomically: true, encoding: .utf8)
        return true
    } catch {}
    return false
}

private func writeHeader(map: LevelMap, buffer: StringBuilder) -> Bool {
    buffer.append("something here ...\n")
    return true
}

Моя відповідь - якщо ви хочете, щоб оригінальне значення, яке бачив абонент, було змінено. Якщо ви просто хотіли мати можливість місцевого переназначення значення, але це не вплине на абонента, інші відповіді, наведені вище, займаються цим.
webjprgm
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.