Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Als u velden wilt delen zonder afzonderlijke modeltypen samen te voegen, gebruikt u recordspreidingen, beschikbaar vanaf F# 11.
Hiermee ...Type kunt u velddeclaraties bijdragen aan een nieuwe benoemde record of ...expression veldwaarden bijdragen aan een benoemde of anonieme record. Declaratie hergebruik en waardetoewijzing zijn onafhankelijke keuzes.
Recordtypen opstellen
Als u verbindingsvelden wilt delen tussen configuratietypen, verspreidt Endpoint u zich over een nieuwe recorddeclaratie:
type Endpoint = { Host: string; Port: int }
type ClientOptions =
{ ...Endpoint
TimeoutSeconds: int }
ClientOptions heeft Host, Porten TimeoutSeconds. Het is een uniek nominaal type, geen Endpoint subtype.
Meerdere bronnen en expliciete declaraties kunnen worden weergegeven in dezelfde typedefinitie:
type Logging = { LogLevel: string }
type LoggedClientOptions = { ...ClientOptions; ...Logging }
Alleen recordvelden nemen deel. Methoden, eigenschappen die geen recordvelden zijn en statische leden worden niet gekopieerd. Een bron kan een benoemde record of een anoniem recordtype zijn, inclusief een afkorting voor een anonieme record. Het doel van een typespreiding moet een benoemd recordtype zijn.
Recordwaarden opstellen
Kopieer het eindpunt naar clientopties en gebruik vervolgens een anonieme record om de host te vervangen:
let local = { Host = "localhost"; Port = 5432 }
let options: ClientOptions = { ...local; TimeoutSeconds = 30 }
let remote = {| ...options; Host = "db.example.com" |}
printn $"{remote.Host}:{remote.Port}, timeout {remote.TimeoutSeconds}s"
// db.example.com:5432, timeout 30s
Expressies accepteren benoemde of anonieme recordbronnen en -bestemmingen, inclusief struct-records. Elk doelveld moet een waarde ontvangen. Een expliciete doelaantekening is handig wanneer meerdere benoemde recordtypen labels delen.
Het type veld versterken
Een latere velddeclaratie kan het type van een verspreid veld vervangen. Vertegenwoordig bijvoorbeeld een geparseerde id met type CustomerId = CustomerId of System.Guiden onderscheid vervolgens een geïmporteerde record van een record met die id:
type ImportedCustomer = { Name: string; Id: string }
type IdentifiedCustomer = { ...ImportedCustomer; Id: CustomerId }
let identify (source: ImportedCustomer) =
match Guid.TryParse source.Id with
| true, id -> Ok ({ ...source; Id = CustomerId id }: IdentifiedCustomer)
| false, _ -> Error "Invalid customer identifier."
Guid.TryParse valideert de tekst; de spread alleen kopieert velden.
CustomerId onderscheidt id's van andere GUID's zonder verdere regels in te stellen.
Onafhankelijke modellen combineren
Stel declaraties op van een gecureerde nominale record en een anoniem recordtype en verzamel vervolgens waarden uit onafhankelijke bronnen:
type PublicProductFields = { Name: string; UnitPrice: decimal }
type ProductRow = { ...PublicProductFields; InternalCost: decimal }
type StockCounts = {| InStock: int; Reserved: int |}
type ProductCard =
{ ...PublicProductFields
...StockCounts
CanOrder: bool }
let product: ProductRow =
{ Name = "Notebook"; UnitPrice = 12.50m; InternalCost = 4m }
let stock: StockCounts = {| InStock = 8; Reserved = 2 |}
let card: ProductCard =
{ ...product; ...stock; CanOrder = stock.InStock > stock.Reserved }
let viewState = {| ...card; Selected = false |}
let selected = {| ...viewState; Selected = true |}
De opgegeven en anonieme bronnen leveren ProductCard; de kaart levert vervolgens de status van anonieme weergave.
CanOrder wordt eenmaal berekend, niet opnieuw berekend wanneer een latere constructie de aantallen wijzigt.
Project in een bekend doel
Een doeltype selecteert de velden die u wilt behouden. Meerdere bronnen kunnen vervangingen leveren:
let endpoint: Endpoint = { ...options }
let overrides = {| Host = "db.example.com"; Port = 5433 |}
let production: ClientOptions =
{ ...options; ...overrides; TimeoutSeconds = 60 }
printn $"{endpoint.Host}:{endpoint.Port}"
printn $"{production.Host}:{production.Port}, timeout {production.TimeoutSeconds}s"
// localhost:5432
// db.example.com:5433, timeout 60s
endpoint houdt alleen Host en Port; production combineert bronnen en expliciete onderdrukkingen. Expliciete velden die ontbreken in het doel blijven fouten.
Een niet-geannoteerde anonieme record neemt alle bijgedragen velden in beslag. Een benoemd doel moet afleiden. Onbekende bronnen hebben hun eigen aantekeningen nodig, zoals (source: ClientOptions) op een functieparameter.
Veldvolgorde en onderdrukkingen
Bijdragen worden van links naar rechts gelezen. Voor een herhaalde veldnaam wint de meest rechtse bijdrage. De regel is zowel van toepassing op velddeclaraties in typen als op veldwaarden in expressies.
let laterHost = {| Host = "db.example.com" |}
let corrected: Endpoint = { ...local; ...laterHost; Port = 5433 }
Nadat een type is overschreven, geeft u een waarde van het vervangende type op. Herhaalde expliciete velden, zoals { Host = "first"; Host = "second" }, blijven fouten.
Voor typedeclaraties wordt een winnende veld weergegeven op de positie van de winnende bijdrage. Velden van een bron behouden hun bronvolgorde. Deze volgorde is van belang voor constructors en handtekeningconformantie.
Evaluatie en kopiëren
Verspreide bronexpressies worden eenmaal uitgevoerd, in de bronvolgorde, zelfs als een latere bijdrage elk veld vervangt dat ze bieden:
let visits = ResizeArray<string>()
let hostFrom source host =
visits.Add source
{| Host = host |}
let selected =
{| ...hostFrom "first" "localhost"
...hostFrom "second" "db.example.com" |}
assert (selected.Host = "db.example.com")
assert (Seq.toList visits = [ "first"; "second" ])
Spreads maken een nieuwe record met ondiepe veldkopieën en dezelfde conversies als expliciete toewijzingen. Onveranderbare objecten waarnaar wordt verwezen door velden blijven gedeeld.
Geneste veldupdates werken met spreads, net als bij kopiëren en bijwerken:
let original = {| Connection = local; Retries = 3 |}
let changed = {| ...original; Connection.Port = 5433 |}
assert (changed.Connection.Port = 5433)
assert (original.Connection.Port = 5432)
Een latere bijdrage om een eerdere geneste update voor dat veld te Connection vervangen. Plaats opzettelijke onderdrukkingen na de spreads die ze moeten overschrijven.
Waarschuwingen over schaduwvelden
Een latere verspreiding kan per ongeluk een expliciete keuze ongedaan maken. De compiler rapporteert deze waarschuwingen standaard:
| Warning | Betekenis |
|---|---|
| FS3897 | Een veld van een type verspreidt schaduwen een eerdere expliciete velddeclaratie. |
| FS3898 | Een veld van een expressie verspreidt schaduwen van een eerder expliciete veldbinding. |
Neemt bijvoorbeeld { Host = "db.example.com"; ...local }Host van local, niet "db.example.com".
Schakel deze opt-inwaarschuwingen in voor een controle van andere overlappingen:
| Warning | Betekenis |
|---|---|
| FS3905 | Een type verspreidt schaduwen een veld van een eerdere typespreiding. |
| FS3906 | Een expliciet veld schaduwt een veld van een eerdere verspreiding. |
| FS3907 | Een expressie verspreidt schaduwen van een veld van een eerdere expressiespreiding. |
<WarnOn>$(WarnOn);3905;3906;3907</WarnOn>
Deze kennisgevingen veranderen het gedrag van meest rechtse wins niet.
Compatibiliteit met weergave en API
Type spreidt de mutabiliteit van het veld en kenmerken op veldniveau. Ze kopiëren geen kenmerken op typeniveau; het eigen [<Struct>] kenmerk van het doel bepaalt de weergave. Argumenten voor brontypen moeten voldoen aan de algemene beperkingen van de bron, inclusief beperkingen voor maateenheden.
Important
Gebruik typespreidingen alleen wanneer gedeelde evolutie opzettelijk is. Een wijziging in het bronveld kan de openbare velden, constructor, kenmerken of beperkingen van de bestemming wijzigen zonder dat deze naar die bestemming hoeft te worden bewerkt.
Spreads omzeilen geen toegankelijkheidscontroles. Null-records zijn geen geldige verspreide bronnen; vaststellen dat een null-waarde niet-null is voordat u deze gebruikt. Cyclische afhankelijkheden via spreads worden geweigerd. Gewone recursieve recordvelden zijn niet alleen verboden omdat de declaratie ook gebruikmaakt van een spread.
Type verspreidt werk in .fsi bestanden. Een handtekening kan expliciete velden gebruiken terwijl de implementatie gebruikmaakt van spreads of omgekeerd, mits de resulterende velden en hun volgorde overeenkomen. Aanhalingstekens bevatten de uitgebreide recordconstructie, niet een verspreid knooppunt.
Spreads kiezen of kopiëren en bijwerken
Gebruik expressies voor kopiëren en bijwerken voor een update van hetzelfde type uit één bron. Gebruik spreads om bronnen te combineren, projecteren naar een ander recordtype of om velddeclaraties opnieuw te gebruiken. Combineer en ... in dezelfde recordexpressie nietwith.
Spreads zijn niet van toepassing op verzamelingen, objectexpressies, willekeurige .NET objecten of C#-records. Ze bieden geen recordpatroonsyntaxis. Recordconstructors zijn een afzonderlijke F# 11.2-functie.