Является ли параметр swift inout переменной или указателем?

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

var shouldContinue: Bool = true

func doSomeWork1(shouldContinue: inout Bool)
{
    while shouldContinue
    {
        // ERROR: the compiler wants: doSomeWork2(shouldContinue: &shouldContinue)
        doSomeWork2(shouldContinue: shouldContinue)
    }
}

func doSomeWork2(shouldContinue: inout Bool)
{
    while shouldContinue
    {

    }
}

Почему компилятор хочет doSomeWork2(shouldContinue: &shouldContinue) вместо the compiler wants: doSomeWork2(shouldContinue: shouldContinue)? не shouldContinue уже указатель в области действия doSomeWork1()???

1 ответ

Решение

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

Параметры In-Out передаются следующим образом:

Когда функция вызывается, значение аргумента копируется.

В теле функции копия модифицируется.

Когда функция возвращается, значение копии присваивается исходному аргументу.

Такое поведение известно как копирование-копирование или результат вызова по значению. Например, когда вычисляемое свойство или свойство с наблюдателями передается как параметр in-out, его метод get вызывается как часть вызова функции, а его метод set вызывается как часть возврата функции.

В качестве оптимизации, когда аргумент является значением, хранящимся по физическому адресу в памяти, одна и та же ячейка памяти используется как внутри, так и снаружи тела функции. Оптимизированное поведение называется вызовом по ссылке; он удовлетворяет всем требованиям модели копирования с копированием при удалении накладных расходов на копирование. Напишите свой код, используя модель, заданную методом copy-in-copy, вне зависимости от оптимизации по вызову, чтобы он работал правильно с оптимизацией или без нее.

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

Из: Мэтт Нойбург Книга "Основы программирования iOS 13 с помощью Swift".:

Если мы хотим, чтобы функция изменяла исходное значение переданного ей аргумента, мы должны сделать следующее:

  • Тип параметра, который мы собираемся изменить, должен быть объявлен inout.
  • Когда мы вызываем функцию, переменная, содержащая изменяемое значение, должна быть объявлена ​​с помощью var, а не let.
  • Вместо того, чтобы передавать переменную в качестве аргумента, мы должны передать ее адрес. Для этого перед его именем ставится амперсанд (&).

Наш removeCharacter(_:from:) теперь выглядит так:

 func removeCharacter(_ c:Character, from s: inout String) -> Int {
  var howMany = 0
  while let ix = s.firstIndex(of:c) {
    s.remove(at:ix)
    howMany += 1
  }
 return howMany
}

И наш вызов removeCharacter(_:from:) теперь выглядит так: var s = "hello" let result = removeCharacter("l", from:&s) После вызова результат равен 2, а s равно "heo". Обратите внимание на амперсанд перед именем s, когда мы передаем его как аргумент from:. Требуется; если вы его опустите, компилятор остановит вас. Мне нравится это требование, потому что оно заставляет нас явно подтвердить компилятору и нам самим, что мы собираемся сделать что-то потенциально опасное: мы позволяем этой функции в качестве побочного эффекта изменять значение вне себя.

Другие вопросы по тегам