Записи (records)
Записи — именованные неизменяемые «корзинки» данных, основа моделирования домена в F#.
Запись (record) — тип с именованными полями; в F# записи по умолчанию неизменяемы и сравниваются по значению (структурное равенство).
Объявление и создание
В отличие от кортежа, у записи поля имеют имена — код самодокументируется.
type Person = {
Name: string
Age: int
}
let alice = { Name = "Алиса"; Age = 30 }
printfn "%s, %d" alice.Name alice.AgeВывод:
Алиса, 30
Тип Person часто даже не нужно указывать при создании — F# выводит его по набору полей.
Неизменяемость и копирование с изменением
Поля записи неизменяемы. Чтобы «поменять» поле, создают копию с изменением через with — старая запись остаётся нетронутой.
type Person = { Name: string; Age: int }
let alice = { Name = "Алиса"; Age = 30 }
let older = { alice with Age = 31 }
printfn "%d -> %d" alice.Age older.AgeВывод:
30 -> 31
Это паттерн функционального обновления: вместо мутации создаётся новое значение. Так данные остаются предсказуемыми.
Структурное равенство
Две записи равны, если равны все их поля — без переопределения equals вручную, как в C#.
type Point = { X: int; Y: int }
let a = { X = 1; Y = 2 }
let b = { X = 1; Y = 2 }
printfn "%b" (a = b)Вывод:
true
Записи в сопоставлении
Поля записи можно разбирать в match.
type Person = { Name: string; Age: int }
let greet p =
match p with
| { Age = 0 } -> "новорождённый"
| { Name = n; Age = a } -> sprintf "%s, %d лет" n a
printfn "%s" (greet { Name = "Боб"; Age = 25 })Вывод:
Боб, 25 лет
Как работает под капотом
Запись компилируется в .NET-класс с приватными полями и свойствами только для чтения. Компилятор автоматически генерирует структурное Equals, GetHashCode и ToString. Конструкция with создаёт новый объект, копируя неизменённые поля и подставляя новые — это поверхностное копирование, поэтому оно дёшево, а исходная запись не страдает.
Частые ошибки
- Пытаться присвоить полю записи новое значение — поля неизменяемы, нужен
with. - Путать записи и классы: запись даёт структурное равенство и краткий синтаксис «из коробки».
- Думать, что
withмутирует исходную запись — он создаёт копию.
Итоги
- Запись — тип с именованными полями, неизменяемый по умолчанию.
- «Изменение» — это копия через
{ запись with Поле = значение }. - Записи сравниваются по значению (структурное равенство) автоматически.
- Поля записи можно разбирать в сопоставлении с образцом.