Быстрые необязательные неточные параметры и ноль

Возможно ли иметь параметр Optional inout для функции в Swift? Я пытаюсь сделать это:

func testFunc( inout optionalParam: MyClass? ) {
    if optionalParam {
        ...
    }
}

... но когда я пытаюсь вызвать его и передаю nil, он дает мне странную ошибку компиляции:

Type 'inout MyClass?' does not conform to protocol 'NilLiteralConvertible'

Я не понимаю, почему мой класс должен соответствовать специальному протоколу, если он уже объявлен как необязательный.

Ответы

Ответ 1

Он не будет компилироваться, потому что функция ожидает ссылку, но вы прошли nil. Проблема не имеет ничего общего с необязательным.

Объявление параметра inout означает, что вы назначите ему какое-то значение внутри тела функции. Как он может присваивать значение nil?

Вам нужно называть его как

var a : MyClass? = nil
testFunc(&a) // value of a can be changed inside the function

Если вы знаете С++, это версия вашего кода на С++ без дополнительных

struct MyClass {};    
void testFunc(MyClass &p) {}
int main () { testFunc(nullptr); }

и у вас есть это сообщение об ошибке

main.cpp:6:6: note: candidate function not viable: no known conversion from 'nullptr_t' to 'MyClass &' for 1st argument

который является эквивалентным полученному вами (но более понятному)

Ответ 2

Это возможно, и это может иметь отношение к Closure.()

Необязательный может иметь значение nil, но он не ожидает нулевого значения. Таким образом, опция будет работать, если вы просто не передали ее функции или не передали переменную типа MyClass? со значением nil. Как и состояния Брайана.

Когда вы пишете функцию, она должна иметь значение по умолчанию как необязательный параметр, например:

func testFunc(inout optionalParam:MyClass?={var nilRef:MyClass?;return &nilRef}()) {
    if optionalParam != nil {
        ...
    }
}

Примечание if optionalParam {...} изменено на if optionalParam != nil {...}

вы не можете обходить optionalParam, не проверив его, т.е. if optionalParam? != nil, поскольку обнуление, optionalParam? завершается с ошибкой, когда optionalParam==nil. ~ note, var a :MyClass? имеет значение nil, пока оно не будет назначено.

Вызов: либо testFunc(optionalParam:&a), либо testFunc(), но никогда testFunc(nil)

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

Далее читайте здесь. Apple пытается изменить формулировку необязательного параметра на "параметры со значениями по умолчанию". К сожалению, они не включили опциональное поведение параметров в эти новые дополнительные вещи. Какова точка передачи нулевых опций в качестве опций, если они не сработают при распаковке. Может быть, это становится глубже в основе того, что эта дополнительная вещь, если ее можно передать перед разворачиванием... Шредингеровский кот

Ответ 3

Точный проход из документов:

Вы можете передавать только переменную в качестве аргумента для параметра in-out. Вы не можете передать значение константы или буква в качестве аргумента, потому что константы и литералы не могут быть изменены. Вы помещаете амперсанд (&) непосредственно перед именем переменных, когда вы передаете его как аргумент inout, чтобы указать, что он может быть изменен с помощью функция.

Обратите внимание, что это (отредактировано) за комментарий @gnasher, вам нужно передать только класс как inout (aka by reference), если вы намерены или хотите разрешить экземпляру быть замененным другим экземпляром и а не только оригинальные модифицированные. Прохождение в документации, которая охватывает это:

Параметры In-Out

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

Вот три теста, которые охватывают использование var и inout.

class Bar : Printable {
    var value = 1

    init(_ value:Int) { self.value = value }
    var description:String { return "Bar is: \(value)" }
}

let bar = Bar(1)
func changeBarWithoutInoutSinceBarIsAClassYaySwift(b:Bar) { b.value = 2 }
changeBarWithoutInoutSinceBarIsAClassYaySwift(bar)
println("after: \(bar)") // 2

var bar2 = Bar(0)
func tryToReplaceLocalBarWithoutInout(var b:Bar) { b = Bar(99) }
tryToReplaceLocalBarWithoutInout(bar2)
println("after: \(bar2)") // 0

var bar3 = Bar(0)
func replaceClassInstanceViaInout(inout b:Bar) { b = Bar(99) }
replaceClassInstanceViaInout(&bar3)
println("after: \(bar3)") // 99

Ответ 4

Возможно, но вам нужно заменить 'inout' на 'var'

Это работает только для аргументов класса, а не для Struct. Объект класса передается как указатель, модификатор "inout" не нужен (и фактически является ошибкой). Атрибут 'var' должен быть добавлен, так как вы хотите изменить его значение внутри функции.