Как именно ключевое слово "let" работает в Swift?

Я прочитал это простое объяснение в руководстве:

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

Но я хочу немного больше деталей, чем это. Если константа ссылается на объект, могу ли я изменить его свойства? Если он ссылается на коллекцию, могу ли я добавить или удалить из нее элементы? Я исхожу из фона С#; это похоже на то, как работает readonly (кроме возможности использовать его в телах метода), а если нет, то как он отличается?

Ответ 1

let немного похож на указатель const в C. Если вы ссылаетесь на объект с let, вы можете изменить его свойства или методы вызова, но вы не можете назначить другой объект этот идентификатор.

let также имеет последствия для коллекций и не-объектов. Если вы ссылаетесь на struct на let, вы не можете изменить его свойства или вызвать какие-либо из его методов mutating func.

Использование let/var с коллекциями работает так же, как mutable/immutable коллекции Foundation: если вы назначаете массив let, вы не можете изменить его содержимое. Если вы ссылаетесь на словарь с let, вы не можете добавлять/удалять пары ключ/значение или назначать новое значение для ключа - это действительно неизменно. Если вы хотите назначить подстроки, добавить или иным образом изменить массив или словарь, вы должны объявить его с помощью var.

(До Xcode 6 beta 3, массивы Swift имели странное сочетание значений и ссылочной семантики и были частично изменены при назначении let -, которые ушли сейчас.)

Ответ 2

Лучше всего думать о let в терминах Static Single Assignment (SSA) - каждая переменная SSA назначается ровно один раз. В функциональных языках, таких как lisp, вы не используете оператор присваивания - имена привязаны к значению ровно один раз. Например, имена y и z ниже привязаны к значению ровно один раз (за вызов):

func pow(x: Float, n : Int) -> Float {
  if n == 0 {return 1}
  if n == 1 {return x}
  let y = pow(x, n/2)
  let z = y*y
  if n & 1 == 0 {
    return z
  }
  return z*x
}

Это поддается более правильному коду, поскольку он обеспечивает неизменность и является побочным эффектом.

Вот как программист императивного стиля может вычислить первые 6 степеней 5:

var powersOfFive = Int[]()
for n in [1, 2, 3, 4, 5, 6] {
    var n2 = n*n
    powersOfFive += n2*n2*n
}

Очевидно, что n2 is является инвариантом цикла, поэтому вместо let можно использовать

var powersOfFive = Int[]()
for n in [1, 2, 3, 4, 5, 6] {
    let n2 = n*n
    powersOfFive += n2*n2*n
}

Но действительно функциональный программист избегал бы всех побочных эффектов и мутаций:

let powersOfFive = [1, 2, 3, 4, 5, 6].map(
    {(num: Int) -> Int in
        let num2 = num*num
        return num2*num2*num})

Ответ 3

Пусть


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

let a = 5  // This is now a constant. "a" can never be changed.
var b = 2  // This is now a variable. Change "b" when you like.

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

let a = 5
let b = someClass()
a = 6  // Nope.
b = someOtherClass()  // Nope.
b.setCookies( newNumberOfCookies: 5 )  // Ok, sure.

Let and Collections


Когда вы назначаете массив константе, элементы больше не могут быть добавлены или удалены из этого массива. Однако значение любого из этих элементов массива может быть изменено.

let a = [1, 2, 3]
a.append(4)  // This is NOT OK. You may not add a new value.
a[0] = 0     // This is OK. You can change an existing value.

Словарь, назначенный константе, никак не может быть изменен.

let a = [1: "Awesome", 2: "Not Awesome"]
a[3] = "Bogus"             // This is NOT OK. You may not add new key:value pairs.
a[1] = "Totally Awesome"   // This is NOT OK. You may not change a value.

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

Ответ 4

Пользователи F # будут чувствовать себя как дома с ключевым словом Swift let.:)

В терминах С# вы можете думать о "let" как "readonly var", если эта конструкция разрешена, то есть идентификатор, который может быть связан только в точке объявления.

Ответ 5

Свойства Swift:

Официальная документация Swift Properties

В своей простейшей форме хранимое свойство является константой или переменной, которая хранится как часть экземпляра определенного класса или структуры. Сохраненные свойства могут быть либо хранимыми в переменной значениями (введенными ключевым словом var), либо постоянными хранимыми свойствами (введенными ключевым словом let).

Пример:

В приведенном ниже примере определяется структура, называемая FixedLengthRange, которая описывает диапазон целых чисел, длина диапазона которых не может быть изменена после ее создания:

struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}

Экземпляры FixedLengthRange имеют переменное хранимое свойство firstValue и константное хранимое свойство, называемое length. В приведенном выше примере length инициализируется при создании нового диапазона и после этого не может быть изменен, поскольку это свойство константы.

Ответ 6

Прежде всего, "Ключевое слово let определяет константу" запутанно для новичков, которые исходят из фона С# (например, меня). После прочтения многих ответов я пришел к выводу, что

На самом деле, в swift нет понятия константы

Константа - это выражение, которое разрешено во время компиляции. Для С# и Java константы должны быть назначены во время объявления:

public const double pi = 3.1416;         // C#
public static final double pi = 3.1416   // Java

Apple doc (определение константы с использованием "let" ):

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

В терминах С# вы можете думать о "let" как "readonly" variable

Swift "let" == С# "readonly"