Как именно ключевое слово "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"