Почему за пределами блока swift не может видеть значение, присвоенное неинициализированной переменной в блоке? - PullRequest
0 голосов
/ 10 мая 2019

Каков механизм объявления значения без в Swift5?Становится ли первое присвоение настоящим объявлением?

И следует ли нам избегать объявления без значения в Swift?

var v:String;
if true {
    v = "Hello"
    print(v) // print "Hello" when without the print below
}
print(v) // variable 'v' used before being initialized
var v:String="";
if true {
    v = "Hello"
    print(v) // print "Hello"
}
print(v) // print "Hello"

Ответы [ 2 ]

2 голосов
/ 10 мая 2019

Ну, сообщение не очень полезно, и в этом проблема. Этот шаблон (который я называю вычисляемой инициализацией ) совершенно легален и полезен, и, что удивительно, вы даже можете использовать let вместо var. Но вы должны инициализировать неинициализированную переменную по всем возможным путям , прежде чем использовать ее. Итак, у вас есть:

var v:String
if true {
    v = "Hello"
}
print(v) // error

Но держи мое пиво и смотри это :

var v:String
if true {
    v = "Hello"
} else {
    v = "Goodbye"
}
print(v) // fine!

Или даже:

let v:String
if true {
    v = "Hello"
} else {
    v = "Goodbye"
}
print(v) // fine!

Удивительно, а?

Теперь вы можете сказать: ОК, но true всегда будет правдой, поэтому глупо заставлять меня выполнять правило "всех путей". Очень плохо! Компилятор настаивает в любом случае, а затем позволяет вам позже с предупреждением, что else не будет выполнен. Но предупреждение позволяет вам скомпилировать; ошибка не Правда в том, что ваш пример очень искусственный. Но это реальная возможность:

let v:String
if self.someBoolProperty {
    v = "Hello"
} else {
    v = "Goodbye"
}
print(v) // fine!

Мало того, что подобные вещи легальны, на самом деле Apple рекомендует шаблон при некоторых немного хитрых обстоятельствах. Например, он используется в собственном примере кода Apple , показывающем, как использовать структуру результатов Swift 5:

let result: Result<Int, EntropyError>
if count < AsyncRandomGenerator.entropyLimit {
    // Produce numbers until reaching the entropy limit.
    result = .success(Int.random(in: 1...100))
} else {
    // Supply a failure reason when the caller hits the limit.
    result = .failure(.entropyDepleted)
}
0 голосов
/ 10 мая 2019

Это происходит потому, что swift компилирует ваш код и замечает, что ваше значение var v:String; необъявлено перед использованием, что делает его "необязательным" значением.Даже если вы присваиваете его в операторе if, если бы вы избавились от значения true, вполне возможно, что оператор if никогда не будет выполняться, поэтому никакое значение никогда не будет сохранено в v, поэтому оно будет использоваться раньше "назначено ".

Таким образом, чтобы ответить на ваш вопрос, если вы хотите, чтобы ваше значение было необязательным и возможным пустым значением, объявите v следующим var v:String?, если вы хотите, чтобы оно было необязательным значением со значениемвсегда хранится в v, вы должны объявить его следующим образом var v = "".Swift будет интерпретировать это объявление как строку.

Чтобы ответить на ваш второй вопрос, определение без значений в swift допускается на 100%, на самом деле это зависит только от того, как вы хотите обработать свой код.Я все время использую необязательные значения в своем коде, но мне не обязательно нравятся необязательные значения, поэтому я обычно хотел бы объявлять свои значения, такие как var v = "", таким образом, если значение пусто, мой пользовательский интерфейс или что-то еще, чем я манипулирую, выиграл 'т перерыв.Но если мне нужно убедиться, что значение присутствует, мне придется сделать мое значение необязательным, чтобы я мог использовать оператор if, чтобы проверить, является ли оно допустимым значением.

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

...