Как избежать «переменной j, записанной, но никогда не считываемой» в Swift?

#swift3 #swift-playground

#swift3 #swift-игровая площадка

Вопрос:

Я использую переменную j для печати ее конечного значения внутри блока отсрочки, как показано ниже:

 func justForFun()
{    
   defer {let x = j; print("(x)")}
   var j = 0
   for i in 1...5
   {
       print("(i)")
       j = i*2;
   }
}
justForFun()
  

Итак, переменная j действительно считывается и печатается внутри блока defer. Тем не менее, PlayGround отображает предупреждение о том, что переменная j записывается, но никогда не читается. Есть ли способ просветить компилятор и избавиться от этого предупреждения?

Ответ №1:

Предупреждение исчезает, если объявление переменной перемещается выше defer .

 $ cat d.swift 
func justForFun() {    
   var j = 0
   defer {let x = j; print("(x)")}
   for i in 1...5 {
       print("(i)")
       j = i*2;
   }
}
justForFun()

$ swift d.swift 
1 
2
3
4
5
10
  

Хотя это не объясняет, почему появляется предупреждение, оно отвечает на вопрос, как вы можете убрать предупреждение.

Что касается просвещения компилятора, я не думаю, что вы можете это сделать. Возможно, вы захотите подать и выдать в swift.org ; см. Эту страницу о том, как сообщить об ошибке. Кажется, что static flow checker не просматривает defer инструкции, которые, я считаю, должны. Хорошая находка.

Комментарии:

1. Есть ли способ присвоить этому ответу отметку «половина галочки», поскольку он ответил на первую часть моего вопроса? Я хотел бы преобразовать это в полную галочку, если другого ответа нет или если моя вторая часть вопроса является известной ошибкой в Swift 3.

2. Это хороший вопрос. Не голосуйте, если это вам не поможет. Вы можете дождаться ответа или попробовать форумы Swift или опубликовать отчет об ошибке и посмотреть, что говорят разработчики. Для меня это похоже на ошибку, но я не могу сказать вам наверняка.

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

4. Надеюсь, вы найдете ответ. Это интересный случай. Если бы Swift принял правило, в котором говорилось, что область действия local распространяется от точки объявления до конца блока, тогда я бы ожидал ошибки компилятора, говорящей, что использование j in в defer блоке не входит в область действия. Тот факт, что появляется предупреждение, довольно странный.

Ответ №2:

Обходной путь

Добавление анонимного присваивания, _ = , устраняет предупреждение:

 // Swift 3.0
func justForFun()
{
  defer {let x = j; print("(x)")}
  var j = 0

  // anonymous assignment:
  _ = j
  for i in 1...5
  {
    print("(i)")
    j = i*2;
  }
}

justForFun()
  

Комментарии:

1. Мои извинения. Я не могу понять ваш комментарий «Что касается …. камней». Пожалуйста, перефразируйте.

2. Хотя я по умолчанию не легкомыслен в SO, мне показалось, что, когда OP назвал свою функцию justForFun() , он задавал беззаботный тон. Но беззаботно! = сбивает с толку. Я удалил эту строку.