RegistrosRecords

Los registros representan agregados simples de valores con nombre, opcionalmente con miembros.Records represent simple aggregates of named values, optionally with members. Pueden ser Structs o tipos de referencia.They can either be structs or reference types. Son tipos de referencia de forma predeterminada.They are reference types by default.

SintaxisSyntax

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

ComentariosRemarks

En la sintaxis anterior, TypeName es el nombre del tipo de registro, Label1 y Label2 son nombres de valores, denominados etiquetas, y Type1 y tipo2 son los tipos de estos valores.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 es la lista opcional de miembros del tipo.member-list is the optional list of members for the type. Puede usar el [<Struct>] atributo para crear un registro struct en lugar de un registro que sea un tipo de referencia.You can use the [<Struct>] attribute to create a struct record rather than a record which is a reference type.

A continuación se muestran algunos ejemplos.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 }

Cuando cada etiqueta está en una línea independiente, el punto y coma es opcional.When each label is on a separate line, the semicolon is optional.

Puede establecer valores en expresiones conocidas como expresiones de registro.You can set values in expressions known as record expressions. El compilador deduce el tipo a partir de las etiquetas utilizadas (si las etiquetas son suficientemente distintas de las de otros tipos de registro).The compiler infers the type from the labels used (if the labels are sufficiently distinct from those of other record types). Las llaves ({}) incluyen la expresión de registro.Braces ({ }) enclose the record expression. En el código siguiente se muestra una expresión de registro que inicializa un registro con tres elementos Float xcon y etiquetas z, y.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; }

No utilice la forma abreviada si puede haber otro tipo que también tenga las mismas etiquetas.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; }

Las etiquetas del tipo declarado más recientemente tienen prioridad sobre las del tipo declarado previamente, por lo que en el ejemplo anterior, mypoint3D se deduce Point3Dque es.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. Puede especificar explícitamente el tipo de registro, como en el código siguiente.You can explicitly specify the record type, as in the following code.

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

Los métodos se pueden definir para tipos de registro del mismo modo que para los tipos de clase.Methods can be defined for record types just as for class types.

Crear registros mediante expresiones de registroCreating Records by Using Record Expressions

Puede inicializar los registros mediante las etiquetas definidas en el registro.You can initialize records by using the labels that are defined in the record. Una expresión que hace esto se conoce como una expresión de registro.An expression that does this is referred to as a record expression. Use llaves para encerrar la expresión de registro y use el punto y coma como delimitador.Use braces to enclose the record expression and use the semicolon as a delimiter.

En el ejemplo siguiente se muestra cómo crear un registro.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; }

Los signos de punto y coma después del último campo de la expresión de registro y de la definición de tipo son opcionales, independientemente de si todos los campos están en una sola línea.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.

Al crear un registro, debe proporcionar valores para cada campo.When you create a record, you must supply values for each field. No se puede hacer referencia a los valores de otros campos de la expresión de inicialización de ningún campo.You cannot refer to the values of other fields in the initialization expression for any field.

En el código siguiente, el tipo de myRecord2 se deduce de los nombres de los campos.In the following code, the type of myRecord2 is inferred from the names of the fields. Opcionalmente, puede especificar el nombre del tipo explícitamente.Optionally, you can specify the type name explicitly.

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

Otra forma de construcción de registros puede ser útil si tiene que copiar un registro existente y, posiblemente, cambiar algunos de los valores de los campos.Another form of record construction can be useful when you have to copy an existing record, and possibly change some of the field values. La siguiente línea de código ilustra esto.The following line of code illustrates this.

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

Esta forma de la expresión de registro se denomina expresión de registro de copia y actualización.This form of the record expression is called the copy and update record expression.

Los registros son inmutables de forma predeterminada; sin embargo, puede crear fácilmente registros modificados mediante una expresión de copia y actualización.Records are immutable by default; however, you can easily create modified records by using a copy and update expression. También puede especificar explícitamente un campo mutable.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

No use el atributo DefaultValue con campos de registro.Don't use the DefaultValue attribute with record fields. Un mejor enfoque es definir instancias predeterminadas de registros con campos que se inicializan con valores predeterminados y, a continuación, usar una expresión de registro de copia y actualización para establecer los campos que difieren de los valores predeterminados.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 }

Crear registros recursivos mutuamenteCreating Mutually Recursive Records

En algún momento al crear un registro, puede que desee que dependa de otro tipo que le gustaría definir después.Sometime when creating a record, you may want to have it depend on another type that you would like to define afterwards. Se trata de un error de compilación a menos que defina los tipos de registro para que sean recursivos mutuamente.This is a compile error unless you define the record types to be mutually recursive.

La definición de registros recursivos mutuamente se realiza and con la palabra clave.Defining mutually recursive records is done with the and keyword. Esto le permite vincular 2 o más tipos de registro juntos.This lets you link 2 or more record types together.

Por ejemplo, el código siguiente define un Person tipo Address y como recursivo mutuamente:For example, the following code defines a Person and Address type as mutually recursive:

// Create a Person type and use the Address type that is not defined
type Person =
  { Name: string
    Age: int
    Address: Address }
// Define the Address type which is used in the Person record
and Address =
  { Line1: string
    Line2: string
    PostCode: string
    Occupant: Person }

Si fuera a definir el ejemplo anterior sin la and palabra clave, no se compilaría.If you were to define the previous example without the and keyword, then it would not compile. La and palabra clave es necesaria para las definiciones mutuamente recursivas.The and keyword is required for mutually recursive definitions.

Coincidencia de patrones con registrosPattern Matching with Records

Los registros se pueden usar con la coincidencia de patrones.Records can be used with pattern matching. Puede especificar algunos campos explícitamente y proporcionar variables para otros campos que se asignarán cuando se produzca una coincidencia.You can specify some fields explicitly and provide variables for other fields that will be assigned when a match occurs. En el siguiente ejemplo código se muestra cómo hacerlo.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 }

El resultado de este código es el siguiente.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).

Diferencias entre los registros y las clasesDifferences Between Records and Classes

Los campos de registro difieren de las clases en que se exponen automáticamente como propiedades y se usan en la creación y copia de registros.Record fields differ from classes in that they are automatically exposed as properties, and they are used in the creation and copying of records. La construcción de registros también difiere de la construcción de clases.Record construction also differs from class construction. En un tipo de registro, no se puede definir un constructor.In a record type, you cannot define a constructor. En su lugar, se aplica la sintaxis de construcción que se describe en este tema.Instead, the construction syntax described in this topic applies. Las clases no tienen ninguna relación directa entre los parámetros de constructor, los campos y las propiedades.Classes have no direct relationship between constructor parameters, fields, and properties.

Al igual que los tipos de estructura y Unión, los registros tienen una semántica estructural de igualdad.Like union and structure types, records have structural equality semantics. Las clases tienen semántica de igualdad de referencia.Classes have reference equality semantics. El siguiente ejemplo de código muestra esto.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."

El resultado de este código es el siguiente:The output of this code is as follows:

The records are equal.

Si escribe el mismo código con clases, los dos objetos de clase no serían iguales porque los dos valores representarían dos objetos en el montón y solo se compararían las direcciones (a menos que el tipo de System.Object.Equals clase invalide el método).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).

Si necesita igualdad de referencia para los registros, agregue el [<ReferenceEquality>] atributo encima del registro.If you need reference equality for records, add the attribute [<ReferenceEquality>] above the record.

Vea tambiénSee also