Record (F#)

I record rappresentano aggregazioni semplici di valori denominati, facoltativamente con membri.

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

Note

Nella sintassi precedente typename è il nome del tipo di record, label1 e label2 sono nomi di valori, detti etichette, e type1 e type2 sono i tipi di questi valori.member-list è l'elenco facoltativo di membri per il tipo.

Di seguito vengono forniti alcuni esempi.

type Point = { x : float; y: float; z: float; }
type Customer = { First : string; Last: string; SSN: uint32; AccountNumber : uint32; }

Quando ogni etichetta è in una riga distinta, il punto e virgola è facoltativo.

È possibile impostare valori in espressioni note come espressioni di record.Il compilatore inferisce il tipo dalle etichette utilizzate (se le etichette sono sufficientemente distinte da quelle di altri tipi di record).L'espressione di record è inclusa tra parentesi graffe ({ }).Nel codice riportato di seguito viene illustrata un'espressione di record che inizializza un record con tre elementi float con etichette x, y e z.

let mypoint = { x = 1.0; y = 1.0; z = -1.0; }

Non utilizzare il formato abbreviato se è possibile che sia presente un altro tipo con le stesse etichette.

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; }

Le etichette del tipo dichiarato più recentemente hanno priorità rispetto a quelle del tipo dichiarato in precedenza, pertanto nell'esempio precedente si deduce che mypoint3D sia Point3D.È possibile specificare il tipo di record in modo esplicito, come nel codice seguente.

let myPoint1 = { Point.x = 1.0; y = 1.0; z = 0.0; }

È possibile definire i metodi per i tipi record in modo analogo ai tipi di classe.

Creazione di record tramite espressioni record

È possibile inizializzare record utilizzando le etichette definite nel record.Un'espressione che consente di eseguire questa operazione è detta espressione record.Utilizzare parentesi graffe per racchiudere l'espressione di record e il punto e virgola come delimitatore.

Nell’esempio seguente viene illustrata la modalità di creazione di un record.

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

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

I punti e virgola dopo l'ultimo campo nell'espressione di record e nella definizione del tipo sono facoltativi, indipendentemente dal fatto che i campi si trovino tutti in una riga.

In fase di creazione di un record è necessario fornire valori per ogni campo.Non è possibile fare riferimento ai valori di altri campi nell'espressione di inizializzazione per un campo.

Nel codice seguente il tipo di myRecord2 viene derivato dai nomi dei campi.Facoltativamente, è possibile specificare il nome del tipo in modo esplicito.

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

Un'altra forma di costruzione di record può essere utile quando è necessario copiare un record esistente ed eventualmente modificare alcuni valori dei campi.Nella riga di codice seguente viene illustrata questa situazione.

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

Questa forma di espressione record viene chiamata espressione record di copia e aggiornamento.

Per impostazione predefinita, i record non sono modificabili. È tuttavia possibile creare agevolmente record modificati tramite un'espressione di copia e aggiornamento.È inoltre possibile specificare in modo esplicito un campo modificabile.

type Car = {
    Make : string
    Model : string
    mutable Odometer : int
    }
let myCar = { Make = "Fabrikam"; Model = "Coupe"; Odometer = 108112 }
myCar.Odometer <- myCar.Odometer + 21

Non utilizzare l'attributo DefaultValue con i campi di record.Un approccio migliore consiste nel definire istanze predefinite di record con campi vengono inizializzati ai valori predefiniti e quindi utilizzare una copia e aggiornare record espressione per impostare tutti i campi che differiscono dai valori predefiniti.

// 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 }

Criteri di ricerca con i record

I record possono essere utilizzati con i criteri di ricerca.È possibile specificare in modo esplicito alcuni campi e fornire variabili per altri campi che verranno assegnati se si verifica una corrispondenza.Questo aspetto è illustrato nell'esempio di codice seguente.

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 }

L'output del codice è il seguente.

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

Differenze tra record e classi

I campi di record presentano alcune differenze rispetto alle classi, in quanto vengono automaticamente esposti come proprietà e utilizzati nella creazione e nella copia di record.Anche la costruzione di record differisce dalla costruzione di classi.In un tipo di record non è possibile definire un costruttore.Viene invece utilizzata la sintassi di costruzione descritta in questo argomento.Le classi non prevedono una relazione diretta tra parametri di costruttori, campi e proprietà.

In modo analogo ai tipi di unione e ai tipi di struttura, i record dispongono di semantica di uguaglianza strutturale.Le classi dispongono di semantica di uguaglianza dei riferimenti.Nell'esempio di codice che segue viene illustrata questa possibilità.

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 si scrive lo stesso codice con le classi, i due oggetti di classe risulterebbero disuguali, poiché i due valori rappresenterebbero due oggetti sull'heap e verrebbero confrontati solo gli indirizzi (a meno che il tipo di classe non esegua l'override del metodo System.Object.Equals).

Vedere anche

Riferimenti

Classi (F#)

Criteri di ricerca [F#]

Altre risorse

Tipi F#

Riferimenti per il linguaggio F#