Sdílet prostřednictvím


Generika

Hodnoty funkcí F#, metody, vlastnosti a agregační typy, jako jsou třídy, záznamy a diskriminované sjednocení, mohou být obecné. Obecné konstrukce obsahují alespoň jeden parametr typu, který obvykle poskytuje uživatel obecného konstruktoru. Obecné funkce a typy umožňují psát kód, který funguje s různými typy bez opakování kódu pro každý typ. Vytvoření obecného kódu může být v jazyce F# jednoduché, protože často je váš kód implicitně odvozen tak, aby byl obecný pomocí odvozování typu kompilátoru a mechanismů automatické generalizace.

Syntaxe

// Explicitly generic function.
let function-name<type-parameters> parameter-list =
function-body

// Explicitly generic method.
[ static ] member object-identifier.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

Poznámky

Deklarace explicitně obecné funkce nebo typu je podobně jako deklarace ne generické funkce nebo typu, s výjimkou specifikace (a použití) parametrů typu v úhlových závorkách za názvem funkce nebo typu.

Deklarace jsou často implicitně obecné. Pokud nezadáte plně typ každého parametru, který se používá k vytvoření funkce nebo typu, kompilátor se pokusí odvodit typ každého parametru, hodnoty a proměnné z kódu, který napíšete. Další informace naleznete v tématu Odvozování typu. Pokud kód pro váš typ nebo funkci jinak neomezuje typy parametrů, je funkce nebo typ implicitně obecný. Tento proces se nazývá automatická generalizace. Existují určitá omezení pro automatickou generalizaci. Pokud například kompilátor jazyka F# nemůže odvodit typy pro obecný konstruktor, kompilátor hlásí chybu, která odkazuje na omezení označované jako omezení hodnoty. V takovém případě možná budete muset přidat některé poznámky k typům. Další informace o automatické zobecnění a omezení hodnoty a o tom, jak změnit kód pro řešení problému, naleznete v tématu Automatické generalizace.

V předchozí syntaxi jsou parametry typu seznam parametrů oddělených čárkami, které představují neznámé typy, z nichž každý začíná jednou uvozovkou, volitelně klauzulí omezení, která dále omezuje, jaké typy lze pro tento parametr typu použít. Syntaxe klauzulí omezení různých druhů a dalších informací o omezeních najdete v tématu Omezení.

Definice typu v syntaxi je stejná jako definice typu pro ne generický typ. Zahrnuje parametry konstruktoru pro typ třídy, volitelnou as klauzuli, symbol rovná se, pole záznamů, inherit klauzuli, volby pro diskriminovanou sjednocení let a do vazby, definice členů a cokoli jiného povoleného v definici ne generického typu.

Ostatní prvky syntaxe jsou stejné jako u obecných funkcí a typů. Například identifikátor objektu je identifikátor , který představuje samotný objekt obsahující.

Vlastnosti, pole a konstruktory nemohou být obecnější než nadřazený typ. Hodnoty v modulu také nemohou být obecné.

Implicitně obecné konstrukce

Když kompilátor jazyka F# odvodí typy v kódu, automaticky zachází s libovolnou funkcí, která může být obecná jako obecná. Pokud zadáte typ explicitně, například typ parametru, zabráníte automatické generalizaci.

V následujícím příkladu kódu je obecný, makeList i když ani jeho parametry nejsou explicitně deklarovány jako obecné.

let makeList a b = [ a; b ]

Podpis funkce je odvozen jako 'a -> 'a -> 'a list. Všimněte si, že ab v tomto příkladu se odvodí, že mají stejný typ. Je to proto, že jsou zahrnuty do seznamu společně a všechny prvky seznamu musí být stejného typu.

Funkci můžete také nastavit jako obecnou pomocí syntaxe jednoduchých uvozovek v poznámce k typu, která označuje, že typ parametru je parametr obecného typu. V následujícím kódu je obecný, function1 protože jeho parametry jsou tímto způsobem deklarovány jako parametry typu.

let function1 (x: 'a) (y: 'a) = printfn "%A %A" x y

Explicitně obecné konstrukce

Funkci můžete také nastavit jako obecnou tím, že explicitně deklarujete parametry jeho typu v hranatých závorkách (<type-parameter>). Následující kód to ilustruje.

let function2<'T> (x: 'T) (y: 'T) = printfn "%A, %A" x y

Použití obecných konstruktorů

Pokud používáte obecné funkce nebo metody, nemusíte zadávat argumenty typu. Kompilátor používá odvození typu k odvození příslušných argumentů typu. Pokud existuje stále nejednoznačnost, můžete zadat argumenty typu v hranatých závorkách a oddělit více argumentů typu čárkami.

Následující kód ukazuje použití funkcí definovaných v předchozích částech.

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

Poznámka:

Existují dva způsoby, jak odkazovat na obecný typ podle názvu. Například list<int> a int list jsou dva způsoby odkazování na obecný typ list , který má jeden typ argument int. Druhý formulář se konvenčně používá pouze s integrovanými typy jazyka F#, jako list jsou a option. Pokud existuje více argumentů typu, obvykle používáte syntaxi Dictionary<int, string> , ale můžete také použít syntaxi (int, string) Dictionary.

Zástupné důkazy jako argumenty typu

Chcete-li určit, že argument typu by měl být odvozen kompilátorem, můžete místo argumentu pojmenovaného typu použít podtržítko nebo zástupný znak (_). To je znázorněno v následujícím kódu.

let printSequence (sequence1: Collections.seq<_>) =
    Seq.iter (fun elem -> printf "%s " (elem.ToString())) sequence1

Omezení v obecných typech a funkcích

V obecném typu nebo definici funkce můžete použít pouze ty konstrukce, o kterých je známo, že jsou k dispozici u parametru obecného typu. To je nutné k povolení ověření volání funkce a metody v době kompilace. Pokud deklarujete parametry typu explicitně, můžete u parametru obecného typu použít explicitní omezení, které kompilátoru oznámí, že jsou k dispozici určité metody a funkce. Pokud však kompilátorU jazyka F# povolíte odvození obecných typů parametrů, určí pro vás příslušná omezení. Další informace najdete v tématu Omezení.

Staticky vyřešené parametry typu

Existují dva druhy parametrů typu, které lze použít v programech jazyka F#. První jsou parametry obecného typu typu popsaného v předchozích částech. Tento první typ parametru typu je ekvivalentní parametrům obecného typu, které se používají v jazycích, jako je Visual Basic a C#. Další druh parametru typu je specifický pro jazyk F# a označuje se jako staticky vyřešený parametr typu. Informace o těchto konstruktorech naleznete v tématu Statically Resolved Type Parameters.

Příklady

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

Viz také