Неизменный в F#
Я знаю, что переменные в F# являются неизменяемыми по умолчанию. Но, например, в F# интерактив:
> let x = 4;;
val x : int = 4
> let x = 5;;
val x : int = 5
> x;;
val it : int = 5
>
Итак, я назначаю 4 х, затем 5 х, и это меняется. Это правильно? Должно ли это дать какую-то ошибку или предупреждение? Или я просто не понимаю, как это работает?
4 ответа
Когда ты пишешь let x = 3
, вы привязываете идентификатор x
к стоимости 3
, Если вы делаете это второй раз в той же области, вы объявляете новый идентификатор, который скрывает предыдущий, так как он имеет то же имя.
Отключение значения в F# осуществляется через оператор деструктивного обновления, <-
, Это не удастся для неизменных значений, то есть:
> let x = 3;;
val x : int = 3
> x <- 5;;
x <- 5;;
^^^^^^
stdin(2,1): error FS0027: This value is not mutable
Чтобы объявить изменчивую переменную, добавьте mutable
после let
:
let mutable x = 5;;
val mutable x : int = 5
> x <- 6;;
val it : unit = ()
> x;;
val it : int = 6
Но в чем разница между двумя, спросите вы? Пример может быть достаточно:
let i = 0;
while i < 10 do
let i = i + 1
()
Несмотря на внешность, это бесконечный цикл. i
объявлено внутри цикла другое i
это скрывает внешнее. Внешний является неизменным, поэтому он всегда сохраняет свою ценность 0
и цикл никогда не заканчивается. Правильный способ написать это с изменяемой переменной:
let mutable i = 0;
while i < 10 do
i <- i + 1
()
x
не изменяется, просто скрывается следующей декларацией. Например:
> let x = 4;;
val x : int = 4
> let x = "abc";;
val x : string = "abc"
>
Вы не назначаете 5 для x
вы определяете новую переменную.
Следующий пример показывает, что есть две разные переменные. (Это также показывает, что вы можете "получить доступ" к старому x, если он находится в замыкании, используемом другой функцией):
let x = 5;;
let f y = y+x;;
f 10;;
let x = 0;;
f 10;;
доходность
>
val x : int = 5
>
val f : int -> int
> val it : int = 15
>
val x : int = 0
> val it : int = 15
как видите, оба вызова f используют первую переменную x
, Определение let x = 0;;
определяет новую переменную x
, но не переопределяет f
,
Вот минимальный пример, иллюстрирующий идентификатор "затенение" (т.е. скрытие) в F#:
let x = 0
do //introduce a new lexical scope
let x = 1 //"shadow" (i.e. hide) the previous definition of x
printfn "%i" x //prints 1
//return to outer lexical scope
printfn "%i" x //prints 0, proving that our outer definition of x was not mutated by our inner definition of x
Ваш пример на самом деле немного сложнее, потому что вы работаете в F# Interactive (FSI). FSI динамически испускает код, который выглядит примерно так в вашем примере:
module FSI_0001 =
let x = 4;;
open FSI_0001 //x = 4 is now available in the top level scope
module FSI_0002 =
let x = 5;;
open FSI_0002 //x = 5 is now available in the top level scope, hiding x = 4
module FSI_0003 =
let it = x;;
open FSI_0003
//... subsequent interactions