ЗаписиRecords

Записи представляют собой простые агрегаты именованных значений, которые могут иметь элементы.Records represent simple aggregates of named values, optionally with members. Начиная с F# 4.1, они может быть структуры или ссылочный тип.Starting with F# 4.1, they can either be structs or reference types. Они являются ссылочными типами, по умолчанию.They are reference types by default.

СинтаксисSyntax

[ attributes ]
type [accessibility-modifier] typename =
    { [ mutable ] label1 : type1;
      [ mutable ] label2 : type2;
      ... }
    [ member-list ]

ПримечанияRemarks

В приведенном выше синтаксисе typename имя типа записи, label1 и label2 — это имена значений, называется метки, и тип1 и тип2 типы из следующих значений.In the previous syntax, typename is the name of the record type, label1 and label2 are names of values, referred to as labels, and type1 and type2 are the types of these values. Список членов — необязательный список элементов для типа.member-list is the optional list of members for the type. Можно использовать [<Struct>] атрибут для создания записи структуры, а не записи, которая является ссылочным типом.You can use the [<Struct>] attribute to create a struct record rather than a record which is a reference type.

Ниже приведены некоторые примеры.Following are some examples.

// Labels are separated by semicolons when defined on the same line.
type Point = { X: float; Y: float; Z: float; }

// You can define labels on their own line with a semicolon.
type Customer = 
    { First: string
      Last: string
      SSN: uint32
      AccountNumber: uint32; }

// A struct record.
[<Struct>]
type StructPoint = 
    { X: float
      Y: float
      Z: float }

При каждой метки находится на отдельной строке, точка с запятой является необязательным.When each label is on a separate line, the semicolon is optional.

Можно задать значения в выражениях, известный как записи выражения.You can set values in expressions known as record expressions. Компилятор выводит тип на основе подписи (если метки в достаточной степени отличаются от других типов записей).The compiler infers the type from the labels used (if the labels are sufficiently distinct from those of other record types). Фигурные скобки ({}) заключите выражение записи.Braces ({ }) enclose the record expression. В следующем коде показано выражение записи, инициализирующее запись с тремя элементами число с плавающей запятой с метками x, y и z.The following code shows a record expression that initializes a record with three float elements with labels x, y and z.

let mypoint = { X = 1.0; Y = 1.0; Z = -1.0; }

Не используйте сокращенную форму, если может быть другой тип, который также имеет одинаковые заголовки.Do not use the shortened form if there could be another type that also has the same labels.

type Point = { X: float; Y: float; Z: float; }
type Point3D = { X: float; Y: float; Z: float }
// Ambiguity: Point or Point3D?
let mypoint3D = { X = 1.0; Y = 1.0; Z = 0.0; }

Метки последнего объявленного типа имеют приоритет над метками ранее объявленного типа, поэтому в приведенном выше примере mypoint3D выводится как Point3D.The labels of the most recently declared type take precedence over those of the previously declared type, so in the preceding example, mypoint3D is inferred to be Point3D. Можно явно указать тип записи, как показано в следующем коде.You can explicitly specify the record type, as in the following code.

let myPoint1 = { Point.X = 1.0; Y = 1.0; Z = 0.0; }

Методы могут определяться для типов записей, так же как и типы классов.Methods can be defined for record types just as for class types.

Создание записей с помощью выражений записейCreating Records by Using Record Expressions

Записи можно инициализировать с помощью метки, которые определены в записи.You can initialize records by using the labels that are defined in the record. Выражение, которое делает это называется записать выражение.An expression that does this is referred to as a record expression. Используйте фигурные скобки для заключите выражение записи и используют в качестве разделителя точку с запятой.Use braces to enclose the record expression and use the semicolon as a delimiter.

В следующем примере показано, как создать запись.The following example shows how to create a record.

type MyRecord = 
    { X: int
      Y: int
      Z: int }

let myRecord1 = { X = 1; Y = 2; Z = 3; }

Точка с запятой после последнего поля в выражении записи и в определении типа являются необязательными, независимо от того, являются ли поля все в одну строку.The semicolons after the last field in the record expression and in the type definition are optional, regardless of whether the fields are all in one line.

При создании записи необходимо указать значения для каждого поля.When you create a record, you must supply values for each field. Нельзя ссылаться на значения других полей в выражении инициализации для любого поля.You cannot refer to the values of other fields in the initialization expression for any field.

В следующем коде, тип myRecord2 выводится из имена полей.In the following code, the type of myRecord2 is inferred from the names of the fields. При необходимости можно явно указать имя типа.Optionally, you can specify the type name explicitly.

let myRecord2 = { MyRecord.X = 1; MyRecord.Y = 2; MyRecord.Z = 3 }

Можно использовать другую форму конструкции записи, при необходимо будет скопировать существующую запись, возможно, изменить некоторые значения полей.Another form of record construction can be useful when you have to copy an existing record, and possibly change some of the field values. Это показано в следующей строке кода.The following line of code illustrates this.

let myRecord3 = { myRecord2 with Y = 100; Z = 2 }

Эта форма выражения записи называется копирование и обновление выражений записей.This form of the record expression is called the copy and update record expression.

Записи являются неизменяемыми по умолчанию; Тем не менее можно легко создать измененные записи с помощью копирования и обновить выражение.Records are immutable by default; however, you can easily create modified records by using a copy and update expression. Можно также явно указать изменяемого поля.You can also explicitly specify a mutable field.

type Car = 
    { Make : string
      Model : string
      mutable Odometer : int }

let myCar = { Make = "Fabrikam"; Model = "Coupe"; Odometer = 108112 }
myCar.Odometer <- myCar.Odometer + 21

Не используйте атрибут DefaultValue с полями записей.Don't use the DefaultValue attribute with record fields. Лучшим подходом является определение экземпляров по умолчанию записей с полями, которые были инициализированы значениями по умолчанию, а затем использовать копию и обновить записи выражение, чтобы задать все поля, которые отличаются от значений по умолчанию.A better approach is to define default instances of records with fields that are initialized to default values and then use a copy and update record expression to set any fields that differ from the default values.

// Rather than use [<DefaultValue>], define a default record.
type MyRecord =
    { Field1 : int
      Field2 : int }

let defaultRecord1 = { Field1 = 0; Field2 = 0 }
let defaultRecord2 = { Field1 = 1; Field2 = 25 }

// Use the with keyword to populate only a few chosen fields
// and leave the rest with default values.
let rr3 = { defaultRecord1 with Field2 = 42 }

Сопоставление шаблонов с записямиPattern Matching with Records

Записи могут использоваться с сопоставлением шаблонов.Records can be used with pattern matching. Можно явным образом задать некоторые поля и указать переменные для других полей, которые будут назначаться при совпадении.You can specify some fields explicitly and provide variables for other fields that will be assigned when a match occurs. Это показано в следующем примере кода.The following code example illustrates this.

type Point3D = { X: float; Y: float; Z: float }
let evaluatePoint (point: Point3D) =
    match point with
    | { X = 0.0; Y = 0.0; Z = 0.0 } -> printfn "Point is at the origin."
    | { X = xVal; Y = 0.0; Z = 0.0 } -> printfn "Point is on the x-axis. Value is %f." xVal
    | { X = 0.0; Y = yVal; Z = 0.0 } -> printfn "Point is on the y-axis. Value is %f." yVal
    | { X = 0.0; Y = 0.0; Z = zVal } -> printfn "Point is on the z-axis. Value is %f." zVal
    | { X = xVal; Y = yVal; Z = zVal } -> printfn "Point is at (%f, %f, %f)." xVal yVal zVal

evaluatePoint { X = 0.0; Y = 0.0; Z = 0.0 }
evaluatePoint { X = 100.0; Y = 0.0; Z = 0.0 }
evaluatePoint { X = 10.0; Y = 0.0; Z = -1.0 }

Результат выполнения этого кода выглядит следующим образом.The output of this code is as follows.

Point is at the origin.
Point is on the x-axis. Value is 100.000000.
Point is at (10.000000, 0.000000, -1.000000).

Различия между записями и классыDifferences Between Records and Classes

Поля записей отличаются от классов, в том, что они автоматически представляются как свойства, и они используются при создании и копировании записей.Record fields differ from classes in that they are automatically exposed as properties, and they are used in the creation and copying of records. Построение записей также отличается от построения класса.Record construction also differs from class construction. В типе записи не может определить конструктор.In a record type, you cannot define a constructor. Вместо этого применяется синтаксис конструкции, описанный в этом разделе.Instead, the construction syntax described in this topic applies. Классы не имеют прямых связей между параметров конструктора, поля и свойства.Classes have no direct relationship between constructor parameters, fields, and properties.

Как и типы объединения и структуру записи имеют семантику структурного равенства.Like union and structure types, records have structural equality semantics. Классы имеют ссылки семантику равенства.Classes have reference equality semantics. Это действие представлено в следующем примере кода:The following code example demonstrates this.

type RecordTest = { X: int; Y: int }

let record1 = { X = 1; Y = 2 }
let record2 = { X = 1; Y = 2 }

if (record1 = record2) then
    printfn "The records are equal."
else
    printfn "The records are unequal."

Результат выполнения этого кода выглядит следующим образом:The output of this code is as follows:

The records are equal.

При написании один и тот же код с классами, два объекта класса будут неравными, так как эти два значения будут представлять два объекта в куче и будут сравниваться только адреса (если тип класса не переопределяет System.Object.Equals метод).If you write the same code with classes, the two class objects would be unequal because the two values would represent two objects on the heap and only the addresses would be compared (unless the class type overrides the System.Object.Equals method).

Если требуется ссылка на равенство для записей, добавьте атрибут [<ReferenceEquality>] выше запись.If you need reference equality for records, add the attribute [<ReferenceEquality>] above the record.

См. такжеSee also