Параметры 'var' устарели и будут удалены в Swift 3.

Хорошо, я просто обновил 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()
}

person SDW    schedule 22.03.2016    source источник
comment
Как насчет public func getQuestionList(inout language: String) -> NSArray   -  person TotoroTotoro    schedule 22.03.2016
comment
Нет, это не подходящая замена. OP, вероятно, не хочет, чтобы у getQuestion были какие-либо побочные эффекты.   -  person BallpointBen    schedule 31.03.2016
comment
Честно говоря, я понятия не имею, почему они даже рассмотрели возможность удаления этого. Это была одна из функций, сделавших Swift потрясающим!   -  person Danny Bravo    schedule 05.04.2016
comment
Сам никогда не пользовался и не разбираюсь в суете.   -  person Mike Taverne    schedule 01.09.2016
comment
@MikeTaverne (поздний ответ) Рассмотрим следующую функцию: func foo(_ bar: int) { /*use bar*/ bar+=1; foo(bar); }. Это невозможно без параметров var. Вам нужно либо создать отдельную переменную внутри функции и скопировать значение, либо пометить параметр как inout. Первый медленный, второй вызывает неопределенное поведение. Многие алгоритмы используют такую ​​рекурсию.   -  person kevin    schedule 22.10.2018
comment
@kevin Почему бы в вашей функции просто не вызвать foo(bar + 1)?   -  person Mike Taverne    schedule 22.10.2018
comment
@MikeTaverne Потому что это простой пример, и то, что вы предлагаете, не всегда возможно. Что, если bar не int, а сложный объект?   -  person kevin    schedule 23.10.2018
comment
@kevin Почему вы думаете, что такую ​​промежуточную переменную нельзя оптимизировать? Или что вы имеете в виду под медленным?   -  person Andreas    schedule 01.11.2018


Ответы (8)


Вы пытались назначить новую переменную

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()
}
person garanda    schedule 22.03.2016
comment
Не совсем то, что, я думаю, хотел ОП. - person brimstone; 23.03.2016
comment
Я бы понял вопрос OP так же, как @garana. OP не использует inout в своем вопросе, они просто изменяют уже существующую переменную локально. - person Eric Aya; 23.03.2016
comment
Полностью согласен, поэтому я не знаю, почему @brimstone проголосовал против моего ответа. Вопрос OP касается изменения значения. - person garanda; 23.03.2016
comment
@garanda На данный момент у вас 3 голоса против и 2 голоса за. Пожалуйста, не предполагайте, кто что проголосовал против. Вы не можете знать. // Эти вопросы и ответы - просто беспорядок. Такое случается. :) - person Eric Aya; 23.03.2016
comment
Собственно, это правильное решение. См. Проблему эволюции Swift, в которой было предложено это изменение: github.com/apple/swift-evolution/blob/master/proposals/ - person Scott Thompson; 23.03.2016
comment
Хотя это отвечает на вопрос OP, значение параметра по умолчанию было бы гораздо лучшим решением. - person Tim Vermeulen; 23.03.2016
comment
@TomSawyer Ты знал, что ввязываешься со Свифтом. Если вы не хотите использовать развивающийся язык, используйте Objective-C. - person Tim Vermeulen; 24.03.2016
comment
@TimVermeulen Все хотят использовать прогрессивный язык. Apple может развивать свой язык разными способами, не меняя синтаксис каждый месяц. Как вы знаете, тонна онлайн-документов и фрагментов кода устарела или устарела из-за Apple. Разработчики вынуждены приходить на этот сайт, чтобы неоднократно обращаться за помощью с множеством глупых вопросов из-за этого. Синтаксис должен быть твердым с самого начала, если Apple хочет, чтобы больше разработчиков преуспели в этом. - person TomSawyer; 24.03.2016
comment
@TomSawyer Изменения синтаксиса пока очень незначительны. Кроме того, программирование всегда было больше связано с глубоким пониманием, чем с базовым синтаксисом. Никто не заставляет вас использовать Swift. Apple меняет синтаксис Swift, чтобы улучшить язык, и я думаю, что пока они отлично справляются со своей задачей. - person Tim Vermeulen; 25.03.2016
comment
Как это может быть решением, если в документе Swift Evolution сказано: «Однако затенение не обязательно является идеальным решением и может указывать на антипаттерн». Мы ожидаем, что пользователи Swift пересмотрят часть своего существующего кода, в котором они используются, но нет строгой необходимости реагировать на это изменение языка. ? - person Just a coder; 26.03.2016
comment
Используйте var language = language, если вы не хотите вводить другое имя переменной (что было основным преимуществом параметра var в первую очередь imo) - person Elijah; 27.03.2016
comment
@Harris, это было потрясающее предложение. вы должны отправить сообщение в качестве ответа, потому что по этой причине другие могут использовать var параметры. ваше решение - лучший подход, поскольку оно не требует введения нового имени переменной. - person Crashalot; 30.03.2016
comment
@TomSawyer, если бы Apple сделала это, язык никогда бы не улучшился. Посмотрите, что случилось с Java: современные языковые функции внедряются в нее десятилетиями, потому что они не могут нарушить обратную совместимость. Для Swift старые двоичные файлы, скомпилированные с 2.2 или даже 1.x, по-прежнему будут работать, и вы по-прежнему можете использовать эти старые версии. Это серьезный релиз по какой-то причине. - person Clashsoft; 17.09.2016

Обсуждение удаления Var из параметра функции полностью задокументировано в этой публикации на GitHub: Удалить параметры переменных

В этом документе вы обнаружите, что люди часто путают var параметры с inout параметрами. Параметр var просто означает, что параметр является изменяемым в контексте функции, в то время как с параметром inout значение параметра в точке возврата будет скопировано из функции в контекст вызывающего.

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

person Tr0yJ    schedule 22.03.2016
comment
Я вообще не понимаю этого изменения, почему необходимость писать еще одну строку для создания изменяемой локальной переменной лучше, чем просто определять параметр как var? - person Ross Barbish; 23.03.2016
comment
Для меня это изменение хорошо, потому что оно подбирает ситуации, когда я должен был реализовать локальную переменную, но я этого не сделал, потому что я выбрал простой выход и принял (старое) предложение Swift о том, чтобы сделать входной параметр var - person dawid; 26.03.2016
comment
Я с @RossBarbish по этому поводу. Итак ... это удаляется, потому что ленивые разработчики не могут различить параметры inout и var? Пффф ... - person Danny Bravo; 05.04.2016
comment
Это кажется ужасно ненужным ... им следовало оставить оба варианта. - person Oscar Gomez; 13.04.2016
comment
Действительно ужасное решение. Логично, что параметр функции var не записывается обратно в исходный входной параметр. Нетрудно понять, что это не внутренняя вещь. Однако теперь мне нужно написать дополнительную строку с var name = name, чтобы иметь возможность изменять параметр внутри функции. Думаю, что-то такое случалось довольно часто. - person Peterdk; 04.03.2017
comment
Вероятно, Swift все равно объявлял локальную переменную поверх параметра за кулисами. Теперь придется делать это вручную. Никаких изменений в производительности, но мы потеряли удобство, чтобы помочь новичкам с простой концепцией. - person mogelbuster; 05.05.2017
comment
Именно поэтому я начал ненавидеть Scala, у него та же проблема. Это ужасное решение, принятое Apple. - person hey_you; 08.07.2019
comment
@hey_you scala разрешает var параметры - person WestCoastProjects; 15.06.2020
comment
@javadba не позволяет использовать параметры var в функциях, только vals. - person hey_you; 16.06.2020

Просто добавьте эту строку в начало функции:

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()
}
person Elijah    schedule 31.03.2016
comment
На сегодняшний день лучший ответ. Требуется изменить только одну строку. - person BallpointBen; 31.03.2016
comment
Но выглядит так неестественно @James - person asyncwait; 19.05.2016
comment
Я считаю, что это лучший ответ, так как он носит то же имя. Подобно тому, как это делают другие распространенные языки. - person Sentry.co; 24.05.2016
comment
Я поддержал этот ответ, потому что он сводит к минимуму изменения кода, но я легко могу представить, что такое повторное использование идентификатора будет запрещено в будущей версии Swift. - person Ian Lovejoy; 07.06.2016
comment
Это может сбить с толку других разработчиков, работающих над вашим проектом. Хотя строка объясняет, что она делает, она не объясняет, почему вам пришлось это сделать. Я бы порекомендовал добавить номер Swift Evolution (SE-0003) в качестве комментария. - person Ruiz; 01.08.2016
comment
@RiverSatya Почему бы просто не использовать параметр напрямую? - person Declan McKenna; 17.10.2016
comment
Параметр неизменяемый. Новую переменную можно изменить. - person Mozahler; 19.07.2017
comment
Действительно отличное предложение. Так мы реализуем это в Swiftify :) - person Crulex; 21.02.2018

Многие люди предлагают параметр 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
person Tim Vermeulen    schedule 22.03.2016
comment
Я также не понимаю, почему все бросились на решение inout, когда OP даже не использовал его в начале ... - person Eric Aya; 23.03.2016
comment
Они предполагали, что var и inout делают то же самое. - person ryantxr; 23.03.2016

Я думаю, что ответы @Harris и @garanda - лучший подход.

В любом случае в вашем случае нет необходимости в var, вы можете:

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

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

Параметры входа-выхода

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

Вы пишете параметр in-out, помещая ключевое слово 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, а затем присваивая временную переменную b.

Вы можете вызвать функцию swapTwoInts (: :) с двумя переменными типа Int, чтобы поменять местами их значения. Обратите внимание, что имена someInt и anotherInt имеют префикс амперсанда, когда они передаются в функцию 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. Параметры ввода-вывода - это альтернативный способ для функции иметь эффект, выходящий за рамки ее тела функции.

person Mustafa Mohammed    schedule 31.01.2017

Вот еще одна идея. Мой вариант использования заключался в том, чтобы передать массив строк для добавления к нему, для чего массив должен передаваться изменчиво. Я тоже не хотел, чтобы в моем классе было такое положение. Итак, я создал класс, содержащий массив, и передал его. В зависимости от вашего варианта использования может показаться глупым иметь класс, содержащий только эту одну переменную.

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
}
person webjprgm    schedule 12.02.2017
comment
Мой ответ: если вы ХОТИТЕ, что исходное значение, как его видит вызывающий абонент, будет изменено. Если вы просто хотели иметь возможность локально переназначить значение, но не влиять на вызывающего абонента, другие ответы выше касаются этого. - person webjprgm; 12.02.2017

person    schedule
comment
code.tutsplus.com / tutorials / - person Abdul Rahman Khan; 04.01.2018