F #: let mutable vs. ref

Во-первых, я признаю, что этот вопрос может быть дублирующим; просто дайте мне знать.

Мне любопытно, какая общая "лучшая практика" для тех ситуаций, когда желательна изменчивость. Кажется, что F # предлагает две возможности для этого: привязка let mutable, которая, похоже, работает как переменные на большинстве языков, и эталонная ячейка (созданная с помощью функции ref), которая требует явного разыменования.

Есть несколько случаев, когда один из них "принудительно" в один или другой:.NET interop имеет тенденцию использовать mutable с <-, а в вычислениях рабочего процесса следует использовать ref с :=. Таким образом, эти случаи довольно ясны, но мне любопытно, что делать, создавая свои собственные изменяемые переменные за пределами этих сценариев. Какое преимущество имеет один стиль над другим? (Возможно, помощь в этом поможет.)

Спасибо! (И извините за "чрезмерное использование" кавычек.)

Ответ 1

Я могу только поддерживать то, что сказал gradbot - когда мне нужна мутация, я предпочитаю let mutable.

Что касается реализации и различий между двумя ячейками ref, в основном реализуется очень простая запись, содержащая изменчивое поле записи. Вы могли бы написать их легко себе:

type ref<'T> =  // '
  { mutable value : 'T } // '

// the ref function, ! and := operators look like this:
let (!) (a:ref<_>) = a.value
let (:=) (a:ref<_>) v = a.value <- v
let ref v = { value = v }

Заметное различие между двумя подходами заключается в том, что let mutable хранит изменяемое значение в стеке (как изменчивую переменную в С#), в то время как ref сохраняет изменчивое значение в поле записи, выделенной кучей. Это может повлиять на производительность, но у меня нет никаких чисел...

Благодаря этому изменяемые значения, которые используют ref, могут быть псевдонимы - это означает, что вы можете создать два значения, которые ссылаются на одно и то же изменяемое значение:

let a = ref 5  // allocates a new record on the heap
let b = a      // b references the same record
b := 10        // modifies the value of 'a' as well!

let mutable a = 5 // mutable value on the stack
let mutable b = a // new mutable value initialized to current value of 'a'
b <- 10           // modifies the value of 'b' only!

Ответ 2

Связанный с этим вопрос: "Вы упомянули, что локальные измененные значения не могут быть захвачены закрытием, поэтому вам нужно использовать ref вместо этого. Причина этого в том, что изменяемые значения, зафиксированные в закрытии, должны быть выделенных в куче (поскольку закрытие выделено в куче)". from F # ref-mutable vars vs object fields

Я думаю, что let mutable предпочтительнее контрольных ячеек. Я лично использую только контрольные ячейки, когда они необходимы.

Большинство написанных мной кодов не используют изменяемые переменные благодаря рекурсивным и хвостовым вызовам. Если у меня есть группа изменяемых данных, я использую запись. Для объектов я использую let mutable для создания частных переменных. Я действительно использую только ссылочные ячейки для замыканий, обычно событий.

Ответ 3

Эта статья Брайана может дать ответ.

Mutables просты в использовании и эффективны (без обертывания), но не могут быть захвачены в лямбдах. Реф-ячейки могут быть захвачены, но являются подробными и менее эффективными (? - не уверены в этом).

Ответ 4

Как описано в этой статье блога MSDN в разделе Упрощенное использование изменяемых значений, вам больше не нужны ref-ячейки для лямбда. Таким образом, вы вообще не нуждаетесь в них.

Ответ 5

Вы можете взглянуть на раздел Mutable Data в wikibook.

Для удобства здесь приведены некоторые релевантные кавычки:

Часто используется изменяемое ключевое слово с типами записей для создания изменчивых записи

Переменные переменные несколько ограничено: mutables недоступны вне сферы действия функции где они определены. В частности, это означает, что ссылка изменена в подфункции другой функции.

Реф-клетки обходят некоторые из ограничения переменных. Фактически, ref ячейки - очень простой тип данных, который завернуть изменчивое поле в записи тип.

Поскольку ячейки ref выделяются на кучи, они могут несколько функций