Typy ogólne (F#)
Funkcja F# wartości właściwości, metod i agregatu typów, takich jak klasy, rekordy i związków dyskryminowanych może być generic.Rodzajowy konstrukcje zawierają co najmniej jeden parametr typu, który jest zazwyczaj dostarczany przez użytkownika rodzajowy konstrukcji.Ogólne funkcje i typy umożliwiają pisanie kodu, który działa z różnych typów bez powtarzania kod dla każdego typu.Sprawia, że kod rodzajowy może być prosty F#, ponieważ często kodu jest niejawnie wywnioskowane być rodzajowy przez kompilator typu wnioskowanie i mechanizmy automatycznego generalizacji.
// Explicitly generic function.
let function-name<type-parameters> parameter-list =
function-body
// Explicitly generic method.
[ static ] member object-identifer.method-name<type-parameters> parameter-list [ return-type ] =
method-body
// Explicitly generic class, record, interface, structure,
// or discriminated union.
type type-name<type-parameters> type-definition
Uwagi
Deklaracja jawnie rodzajowy funkcję lub typ przypomina nierodzajową funkcję lub typ, z wyjątkiem specyfikacji (i użycia) parametry typu w nawiasy po nazwie funkcji lub typu.
Deklaracje często są niejawnie rodzajowy.Jeśli nie określisz pełni typ każdego parametru, który jest używany do redagowania funkcję lub typ, kompilator próbuje rozpoznać typ każdego parametru, wartość i zmiennej z programowanego kodu.Aby uzyskać więcej informacji, zobacz Wnioskowanie o typie (F#).Jeśli kod dla typu lub funkcji w przeciwnym razie nie ograniczyć typy parametrów, funkcję lub typ jest niejawnie rodzajowy.Ten proces nosi nazwę Automatyczne generalizacji.Istnieją pewne ograniczenia na automatyczne generalizacji.Na przykład, jeśli kompilator F# nie jest w stanie rozpoznać typy rodzajowe konstrukcji, kompilator zgłasza błąd, który odnosi się do ograniczenia o nazwie ograniczenie wartości.W takim przypadku może mieć dodawać adnotacje niektóre typu.Aby uzyskać więcej informacji na temat automatycznego Generalizacja i ograniczenie wartości i jak zmienić kod, aby rozwiązać ten problem, zobacz Automatyczna generalizacja (F#).
W poprzednich składni type-parameters jest rozdzielana przecinkami lista parametrów, które reprezentują nieznane typy, z których każdy rozpoczyna się od pojedynczego cudzysłowu, opcjonalnie z klauzuli constraint, która ogranicza dalsze jakie typy może być używany dla tego parametru typu.Składnia klauzul constraint różnego rodzaju i inne informacje o ograniczeniach, zobacz Ograniczenia (F#).
type-definition w składnia jest taka sama jak definicji typu dla typu nie uniwersalne.Zawiera parametry konstruktora dla typu klasy, opcjonalny as klauzuli, równe symbol, pola rekordu inherit klauzuli, wybór dyskryminowanych Unii, let i do wiązania, Członkowskie definicje i nic dozwolone w definicji typu nie uniwersalne.
Inne elementy składni są takie same, jak te funkcje-uniwersalne i typów.Na przykład object-identifier jest identyfikatorem, który reprezentuje zawierające samego obiektu.
Właściwości pól i konstruktorzy nie może być bardziej ogólne niż typ otaczający.Ponadto wartości w module nie mogą być podstawowe.
Konstrukcje niejawnie rodzajowy
Gdy kompilator F# ustala typy w kodzie, automatycznie traktuje jakiejkolwiek funkcji, która może być rodzajowy jako rodzajowy.Jeśli możesz określić typ jawnie, takie jak typ parametru, uniemożliwia automatyczne generalizacji.
W poniższym przykładzie kodu makeList jest rodzajowy, mimo że jej ani jej parametry są jawnie deklarowane jako rodzajowy.
let makeList a b =
[a; b]
Podpis funkcji jest niezamierzone za 'a -> 'a -> 'a list.Należy zauważyć, że a i b w tym przykładzie są wywnioskować o takim samym typie.Jest tak, ponieważ są one ze sobą uwzględnione na liście, a wszystkie elementy listy muszą być tego samego typu.
Ci funkcja generic za pomocą składni pojedynczy cudzysłów w wskazania typu, aby wskazać, że typ parametru jest parametr typu rodzajowego.W poniższym kodzie function1 jest rodzajowy, ponieważ jego parametry są deklarowane w ten sposób jako parametrów typu.
let function1 (x: 'a) (y: 'a) =
printfn "%A %A" x y
Konstrukcje jawnie rodzajowy
Można także wprowadzić funkcję rodzajowy przez jawne deklarowanie jej parametry typu w nawiasy ostre (< >).Poniższy kod ilustruje to.
let function2<'T> x y =
printfn "%A, %A" x y
Za pomocą rodzajowy konstrukcje
Gdy używasz ogólne funkcje lub metody, nie trzeba określić argumenty typu.Kompilator używa typu wnioskowanie do wywnioskować argumentów właściwego typu.Jeśli jest nadal niejednoznaczności, może dostarczyć argumentów typu w nawiasy, oddzielając przecinkami wiele argumentów typu.
Poniższy kod przedstawia wykorzystanie funkcji, które są zdefiniowane w poprzednich sekcjach.
// In this case, the type argument is inferred to be int.
function1 10 20
// In this case, the type argument is float.
function1 10.0 20.0
// Type arguments can be specified, but should only be specified
// if the type parameters are declared explicitly. If specified,
// they have an effect on type inference, so in this example,
// a and b are inferred to have type int.
let function3 a b =
// The compiler reports a warning:
function1<int> a b
// No warning.
function2<int> a b
[!UWAGA]
Aby odwołać się za pomocą nazwy do typu rodzajowego na dwa sposoby.Na przykład list<int> i int list są dwa sposoby, aby odwołać się do typu rodzajowego list , ma argumentu typu pojedynczy int.Formularz ten ostatni jest powszechnie używane tylko z wbudowanych typów F# takich jak list i option.Jeśli istnieje wiele argumentów typu, zwykle użyj składni Dictionary<int, string> , ale można również używać składni (int, string) Dictionary.
Symbole wieloznaczne jako argumentów typu
Aby określić, że argument typu należy się ich doszukiwać przez kompilator, można użyć znaku podkreślenia lub symbol wieloznaczny (_) zamiast argumentu nazwanego typu.To jest pokazane w poniższym kodzie.
let printSequence (sequence1: Collections.seq<_>) =
Seq.iter (fun elem -> printf "%s " (elem.ToString())) sequence1
Ograniczenia w typach podstawowych i funkcje
Typ rodzajowy lub definicji funkcji można użyć tylko konstrukcje, które są znane jako dostępne na parametr typu rodzajowego.Jest to wymagane w celu umożliwienia weryfikacji wywołań funkcji i metody w czasie kompilacji.Jeżeli parametry typu jest jawnie deklarować, jawnych ograniczenia mogą dotyczyć parametr typu rodzajowego powiadomić kompilator niektórych metod i funkcje są dostępne.Jednak jeśli zezwolisz na wywnioskować swoje typów parametru rodzajowego kompilator F#, to określi właściwe ograniczenia dla Ciebie.Aby uzyskać więcej informacji, zobacz Ograniczenia (F#).
Statycznie rozwiązane parametrów typu
Istnieją dwa rodzaje parametrów typu, które mogą być używane w programach F#.Pierwszy to parametry typu rodzajowego tego rodzaju, opisane w poprzednich sekcjach.Ten rodzaj pierwszego parametru type jest równoważne parametry typu rodzajowego, które są używane w językach takich jak Visual Basic i C#.Innego rodzaju parametru type jest specyficzne dla F# i nazywa się statycznie rozpoznać typu parametru.Informacje o tych konstrukcji, zobacz Statycznie rozwiązywane parametry typu (F#).
Przykłady
// A generic function.
// In this example, the generic type parameter 'a makes function3 generic.
let function3 (x : 'a) (y : 'a) =
printf "%A %A" x y
// A generic record, with the type parameter in angle brackets.
type GR<'a> =
{
Field1: 'a;
Field2: 'a;
}
// A generic class.
type C<'a>(a : 'a, b : 'a) =
let z = a
let y = b
member this.GenericMethod(x : 'a) =
printfn "%A %A %A" x y z
// A generic discriminated union.
type U<'a> =
| Choice1 of 'a
| Choice2 of 'a * 'a
type Test() =
// A generic member
member this.Function1<'a>(x, y) =
printfn "%A, %A" x y
// A generic abstract method.
abstract abstractMethod<'a, 'b> : 'a * 'b -> unit
override this.abstractMethod<'a, 'b>(x:'a, y:'b) =
printfn "%A, %A" x y
Zobacz też
Informacje
Statycznie rozwiązywane parametry typu (F#)
Inne zasoby
Materiały referencyjne dotyczące języka F#