Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Om du vill dela fält utan att sammanfoga distinkta modelltyper använder du postspridningar som är tillgängliga från och med F# 11.
Använd ...Type för att bidra med fältdeklarationer till en ny namngiven post eller ...expression för att bidra med fältvärden till en namngiven eller anonym post. Återanvändning av deklarationer och värdemappning är oberoende alternativ.
Skapa posttyper
Om du vill dela anslutningsfält mellan konfigurationstyper sprids du Endpoint till en ny postdeklaration:
type Endpoint = { Host: string; Port: int }
type ClientOptions =
{ ...Endpoint
TimeoutSeconds: int }
ClientOptions har Host, Portoch TimeoutSeconds. Det är en distinkt nominell typ, inte en Endpoint undertyp.
Flera källor och explicita deklarationer kan visas i samma typdefinition:
type Logging = { LogLevel: string }
type LoggedClientOptions = { ...ClientOptions; ...Logging }
Endast postfält deltar. Metoder, egenskaper som inte är postfält och statiska medlemmar kopieras inte. En källa kan vara en namngiven post eller en anonym posttyp, inklusive en förkortning för en anonym post. Målet för en typspridning måste vara en namngiven posttyp.
Skapa postvärden
Kopiera slutpunkten till klientalternativ och använd sedan en anonym post för att ersätta värden:
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
Uttrycksspridningar accepterar namngivna eller anonyma postkällor och mål, inklusive structposter. Varje målfält måste få ett värde. En explicit målanteckning är användbar när flera namngivna posttyper delar etiketter.
Stärka ett fälts typ
En senare fältdeklaration kan ersätta typen av ett spridningsfält. Du kan till exempel representera en parsad identifierare med type CustomerId = CustomerId of System.Guidoch sedan skilja en importerad post från en med identifieraren:
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 validerar texten. spridningen kopierar bara fält.
CustomerId särskiljer identifierare från andra GUID utan att införa ytterligare regler.
Kombinera oberoende modeller
Skriv deklarationer från en kuraterad nominell post och en anonym posttyp och sammanställ sedan värden från oberoende källor:
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 |}
Namngivna och anonyma källor anger ProductCard. Kortet tillhandahåller sedan anonymt visningstillstånd.
CanOrder beräknas en gång, inte beräknas om när en senare konstruktion ändrar antalet.
Project till ett känt mål
En måltyp väljer de fält som ska behållas. Flera källor kan tillhandahålla ersättningar:
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 håller bara Host och Port; production kombinerar källor och explicita åsidosättningar. Explicita fält som saknas från målet förblir fel.
En anonym post som inte har kommenterats tar alla bidragsfält. Ett namngivet mål måste kunna härledas. Okända källor behöver egna anteckningar, till exempel (source: ClientOptions) på en funktionsparameter.
Fältordning och åsidosättningar
Bidrag läse från vänster till höger. För ett upprepat fältnamn vinner det högra bidraget. Regeln gäller både fältdeklarationer i typer och fältvärden i uttryck.
let laterHost = {| Host = "db.example.com" |}
let corrected: Endpoint = { ...local; ...laterHost; Port = 5433 }
Efter en typ åsidosättning anger du ett värde av ersättningstypen. Upprepade explicita fält, till exempel { Host = "first"; Host = "second" }, förblir fel.
För typdeklarationer visas ett vinnande fält vid positionen för det vinnande bidraget. Fält från en källa behåller sin källordning. Den här ordningen är viktig för konstruktorer och signaturefterlevnad.
Utvärdering och kopiering
Utspritt källuttryck körs en gång var, i källordning, även om ett senare bidrag ersätter varje fält som de tillhandahåller:
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" ])
Spridningar skapar en ny post med ytliga fältkopior och samma konverteringar som explicita tilldelningar. Föränderliga objekt som refereras av fält förblir delade.
Kapslade fältuppdateringar fungerar med spridningar, som de gör med kopiering och uppdatering:
let original = {| Connection = local; Retries = 3 |}
let changed = {| ...original; Connection.Port = 5433 |}
assert (changed.Connection.Port = 5433)
assert (original.Connection.Port = 5432)
Ett senare bidrag till Connection ersätter en tidigare kapslad uppdatering av fältet. Placera avsiktliga åsidosättningar efter de spridningar som de ska åsidosätta.
Varningar om skuggade fält
En senare spridning kan oavsiktligt ångra ett explicit val. Kompilatorn rapporterar dessa varningar som standard:
| Warning | Meaning |
|---|---|
| FS3897 | Ett fält från en typspridning skuggar en tidigare explicit fältdeklaration. |
| FS3898 | Ett fält från ett uttryck som sprids skuggar en tidigare explicit fältbindning. |
Tar till exempel { Host = "db.example.com"; ...local }Host från local, inte "db.example.com".
Om du vill granska andra överlappningar aktiverar du dessa opt-in-varningar:
| Warning | Meaning |
|---|---|
| FS3905 | En typspridning skuggar ett fält från en tidigare typspridning. |
| FS3906 | Ett explicit fält skuggar ett fält från ett tidigare uppslag. |
| FS3907 | Ett uttryck som sprids skuggar ett fält från ett tidigare uttrycksspridning. |
<WarnOn>$(WarnOn);3905;3906;3907</WarnOn>
Dessa meddelanden ändrar inte beteendet längst till höger vinner.
Representations- och API-kompatibilitet
Typ sprider kopieringsfältets föränderlighet och fältnivåattribut. De kopierar inte attribut på typnivå. målets eget [<Struct>] attribut avgör dess representation. Argument av källtyp måste uppfylla källans allmänna begränsningar, inklusive begränsningar för måttenheter.
Important
Använd endast typspridningar när delad utveckling är avsiktlig. En källfältsändring kan ändra målets offentliga fält, konstruktor, attribut eller begränsningar utan redigering till målet.
Spridningar kringgår inte hjälpmedelskontroller. Nullbara poster är inte giltiga spridningskällor. fastställa att ett null-värde inte är null innan du använder det. Cykliska beroenden via spridningar avvisas . Vanliga rekursiva postfält är inte förbjudna bara för att deklarationen också använder en spridning.
Typspridningar fungerar i .fsi filer. En signatur kan använda explicita fält medan implementeringen använder spridningar, eller det omvända, förutsatt att de resulterande fälten och deras ordning är överens. Citattecken innehåller den utarbetade postkonstruktionen, inte en spridningsnod.
Välj spridningar eller kopiera och uppdatera
Använd kopierings- och uppdateringsuttryck för en uppdatering av samma typ från en källa. Använd spridningar för att kombinera källor, projicera till en annan posttyp eller återanvända fältdeklarationer. Kombinera with inte och ... i samma postuttryck.
Spridningar gäller inte för samlingar, objektuttryck, godtyckliga .NET objekt eller C#-poster. De tillhandahåller inte postmönstersyntax. Postkonstruktorer är en separat F# 11.2-funktion.