Record

Последнее обновление: 11.12.2023

Record (записи) представляет типы, которые позволяет сгруппировать именнованные значения. То есть каждому значению внутри внутри record сопоставляется некоторое имя.

Для определения record применяется оператор type, после которого идет имя записи:

type имя_записи =
    { метка1 : тип_метки1
      метка2 : тип_метки2
      ..........................
      меткаN : тип_меткиN
    }

Внутри фигурных скобок указываются метки/свойства записи в виде пар имя - тип метки, которые разделены двоеточием. Если пары имя-тип размещаются на одной строке, то они разделяются точкой с запятой. Например, определим простейшую запись:

type person = {Name:string; Age:int}

Данная запись называется person. Она определяет два свойства - Name, которое представляет строку, и Age, которое представляет число.

Для определения значения подобного типа применяются фигурные скобки, внутри которых перечисляются свойства их значения

После этого мы можем получить значение этого типа:

type person = {Name:string; Age:int}
let tom = {Name="Tom"; Age=39}

Здесь определено одно значение типа person - значение tom, в котором свойство Name равно "Tom", а Age равно 39.

Обращение к меткам записей

Для обращения к меткам записи применяется точечная нотация:

запись.свойство

Например:

type person = {Name:string; Age:int}
let tom = {Name= "Tom"; Age=39}

printfn $"Name {tom.Name}  Age:{tom.Age}"   // получение значений

Стоит отметить, что по умолчанию значения меток записей неизменяемы. Чтобы их можно было изменить, они должны быть определены с оператором mutable:

type person = {
    Name:string
    mutable Age:int     // изменяемое метка 
}
let tom = {Name= "Tom"; Age=39}
tom.Age <- 22
printfn $"Name: {tom.Name}  Age: {tom.Age}"   // Name: Tom  Age: 22

Создание одной записи на основе другой

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

type person = { Name:string; Age:int }
let tom = {Name= "Tom"; Age=39}

let bob = {tom with Name="Bob"} // создаем запись bob на основе tom

printfn $"Name: {bob.Name}  Age: {bob.Age}"   // Name: Bob  Age: 39

В данном случае создаем значение bob на основе значения tom, при этом устанавливая другое значение для свойства Name.

Компоненты записей

Кроме меток записи могут определять дополнительные свойства и методы, которые предваряются ключевым словом member. Например:

type Person = 
    { Name:string
      Age:int }
    member this.RecordName = "Person"
    member this.Print() = 
        printfn "Name: %s" this.Name 
        printfn "Age: %d" this.Age

let tom = {Name= "Tom"; Age=39}
tom.Print()                         // Name: Tom  Age: 39
printfn "Type: %s" tom.RecordName   // Type: Person

В данном случае дополнительно определено два члена записи - свойство RecordName и функция Print. RecordName представляет название типа записи, а функция Print выводит значения записи на консоль. Причем эти компоненты определены как компоненты экземпляра типа - через ключевое слово this, которое указывает на текущий объект записи.

member this.RecordName
member this.Print() 

Благодаря этому внутри функции Print мы можем обратиться к значениям текущей записи опять же через слово this, а при обращении к этим компонентам применяется имя объекта записи (в примере выше объекта tom):

let tom = {Name= "Tom"; Age=39}
tom.Print()                         // Name: Tom  Age: 39
printfn "Type: %s" tom.RecordName   // Type: Person

Стоит отметить, что свойства записей неизменяемы, и в примере выше мы бы не смогли изменить значение свойства RecordName. Однако в данном случае значение этого свойства не зависит от конкретного объекта записи Person - оно будет для всех одинаково. В этом случае мы могли бы сделать его статическим:

type Person = 
    { Name:string
      Age:int }
    static member RecordName = "Person" // статическое свойство
    member this.Print() = 
        printfn "Name: %s" this.Name 
        printfn "Age: %d" this.Age

printfn "Type: %s" Person.RecordName   // обращение через имя типа

В данном случае свойство RecordName определено как статическое - с ключевым словом static, поэтому оно относится не к отдельным экземплярам Person, а ко всему типа Person в целом. Соотвественно для обращения к нему применяется имя типа, а не имя объекта:

Person.RecordName

Записи-структуры

По умолчанию значения типов Record представляют ссылочные типы, которые размещаются в хипе. Однако мы также можем определить их как структуры, которые будут размещаться в стеке. Для этого перед типом указывается атрибут []

[<Struct>]
type Person = 
    { Name:string
      Age:int }
    member this.Print() = printfn $"Name: {this.Name}   Age: {this.Age}"

let tom = {Name= "Tom"; Age=39}
tom.Print()                         // Name: Tom  Age: 39
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850