Registros (F#)
Registros representam agregações simples de valores nomeados, opcionalmente com membros.
[ attributes ]
type [accessibility-modifier] typename = {
[ mutable ] label1 : type1;
[ mutable ] label2 : type2;
...
}
member-list
Comentários
Na sintaxe anterior, typename é o nome do tipo de registro, label1 e label2 são nomes de valores, conhecidos como rótulos, e type1 e type2 são os tipos desses valores. member-listé a lista opcional de membros para o tipo.
Estes são alguns exemplos.
type Point = { x : float; y: float; z: float; }
type Customer = { First : string; Last: string; SSN: uint32; AccountNumber : uint32; }
Quando cada rótulo em uma linha separada, a vírgula é opcional.
Você pode definir valores em expressões, conhecidas como expressões de registro. O compilador infere o tipo de rótulos usada (se os rótulos são suficientemente diferentes daquelas de outros tipos de registro). Chaves ({}), coloque-a expressão do registro. O código a seguir mostra uma expressão de registro que inicializa um registro com três elementos de float com rótulos x, y e z.
let mypoint = { x = 1.0; y = 1.0; z = -1.0; }
Não use a forma abreviada se pode haver outro tipo que também possui os mesmos rótulos.
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; }
Os rótulos do tipo foi declarado por recentemente têm precedência sobre aquelas do tipo declarado anteriormente, portanto, o exemplo anterior, mypoint3D é inferido para ser Point3D. Você pode especificar explicitamente o tipo de registro, como no código a seguir.
let myPoint1 = { Point.x = 1.0; y = 1.0; z = 0.0; }
Métodos podem ser definidos para os tipos de registro como para os tipos de classe.
A criação de registros usando expressões de registro
Você pode inicializar registros usando os rótulos que são definidos no registro. Uma expressão que faz isso é conhecida como um registro expressão. Use chaves para colocar a expressão de registro e usar vírgula como um delimitador.
O exemplo a seguir mostra como criar um registro.
type MyRecord = {
X: int;
Y: int;
Z: int
}
let myRecord1 = { X = 1; Y = 2; Z = 3; }
A ponto e vírgula após o último campo na expressão do registro e na definição de tipo é opcional, independentemente de estarem campos todas em uma linha.
Quando você cria um registro, você deve fornecer valores para cada campo. Você não pode se referir os valores de outros campos na expressão de inicialização para qualquer campo.
No código a seguir, o tipo de myRecord2 é inferido dos nomes dos campos. Opcionalmente, você pode especificar o nome do tipo explicitamente.
let myRecord2 = { MyRecord.X = 1; MyRecord.Y = 2; MyRecord.Z = 3 }
Outra forma de construção do Registro pode ser útil quando você tem um registro existente e, possivelmente, a alteração de alguns dos valores de campo. A linha de código a seguir ilustra isso.
let myRecord3 = { myRecord2 with Y = 100; Z = 2 }
Este formulário da expressão de registro é chamado de copiar e atualizar o registro de expressão.
Registros são imutáveis por padrão. No entanto, você pode criar facilmente os registros modificados usando uma expressão de cópia e atualização. Também explicitamente, você pode especificar um campo mutável.
type Car = {
Make : string
Model : string
mutable Odometer : int
}
let myCar = { Make = "Fabrikam"; Model = "Coupe"; Odometer = 108112 }
myCar.Odometer <- myCar.Odometer + 21
Padrões coincidentes com registros
Registros podem ser usados com a correspondência de padrões. Você pode especificar explicitamente o alguns campos e fornecer variáveis para outros campos que serão atribuídos quando houver uma correspondência. O exemplo de código a seguir ilustra isso.
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 }
A saída desse código é o seguinte.
Point is at the origin.
Point is on the x-axis. Value is 100.000000.
Point is at (10.000000, 0.000000, -1.000000).
Diferenças entre Classes e registros
Campos do registros diferem das classes que são expostas automaticamente como propriedades e elas são usadas na criação e cópia de registros. Construção de registro também difere da construção de classe. Em um tipo de registro, você não pode definir um construtor. Em vez disso, a sintaxe de construção descrita neste tópico se aplica. Classes não têm nenhuma relação direta entre os parâmetros do construtor, campos e propriedades.
Como os tipos de união e a estrutura, registros possuem semântica de igualdade estrutural. Classes têm referência semântica de igualdade. O código a seguir mostra um exemplo disso:
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."
Se você escrever o mesmo código com classes, os objetos da dois classe seria desiguais porque os dois valores representaria dois objetos na heap e somente os endereços poderiam ser comparados (a menos que o tipo de classe substitui o System.Object.Equals método).
Consulte também
Referência
Outros recursos
Histórico de alterações
Date |
History |
Motivo |
---|---|---|
Maio de 2010 |
Aperfeiçoada a alguns exemplos de código. |
Aprimoramento de informações. |