Megosztás a következőn keresztül:


Statikusan feloldott típusparaméterek

A statikusan feloldott típusparaméter olyan típusparaméter, amelyet a rendszer a fordítási időpontban a tényleges típusra cserél le a futási idő helyett.

Syntax

'type-parameter

Az F# 7.0-s verziójáig az alábbi szintaxist kellett használni

^type-parameter

Megjegyzések

Az F#-ban kétféle típusparaméter létezik. Az első típus a szabványos általános típusparaméter. Ezek egyenértékűek más .NET-nyelvek általános típusparaméterekkel. A másik típus statikusan oldható fel, és csak beágyazott függvényekben használható.

A statikusan feloldott típusparaméterek elsősorban a tagkorlátozásokkal együtt hasznosak, amelyek olyan megkötések, amelyek lehetővé teszik annak megadását, hogy egy típusargumentumnak egy adott taggal vagy taggal kell rendelkeznie a használathoz. Ezt a kényszert nem lehet normál általános típusparaméter használatával létrehozni.

Az alábbi táblázat a típusparaméterek két típusa közötti hasonlóságokat és különbségeket foglalja össze.

Szolgáltatás Általános Statikusan feloldva
Megoldási idő Lefutási idő Fordítási idő
Tagkorlátozások Tagkorlátozásokkal nem használható. Tagkorlátozásokkal használható.
Kódgenerálás A standard általános típusparaméterekkel rendelkező típus (vagy metódus) egyetlen általános típus vagy metódus létrehozását eredményezi. A rendszer több típus- és metódus-példányt hoz létre, amelyek mindegyike szükséges.
Használat típusokkal Típusok esetén használható. Típusokon nem használható.
Használat beágyazott függvényekkel A beágyazott függvények nem paraméterezhetők szabványos általános típusparaméterrel. Ha a bemenetek nem teljesen általánosak, az F#-fordító specializálja őket, vagy ha nincs lehetőség a specializálásra, hibaüzenetet ad. A statikusan feloldott típusparaméterek nem használhatók beágyazott függvényeken vagy metódusokon.

Számos F# alapvető kódtárfüggvény, különösen az operátorok statikusan feloldott típusparaméterekkel rendelkeznek. Ezek a függvények és operátorok beágyazottak, és hatékony kódgenerálást eredményeznek a numerikus számításokhoz.

A beágyazott metódusok és függvények, amelyek operátorokat használnak, vagy más, statikusan feloldott típusparaméterekkel rendelkező függvényeket használnak, maguk is használhatnak statikusan feloldott típusparamétereket. A típuskövetkezmények gyakran arra következtetnek, hogy az ilyen beágyazott függvények statikusan feloldott típusparaméterekkel rendelkeznek. Az alábbi példa egy operátordefiníciót mutat be, amely arra következtet, hogy statikusan feloldott típusparaméterrel rendelkezik.

let inline (+@) x y = x + x * y
// Call that uses int.
printfn "%d" (1 +@ 1)
// Call that uses float.
printfn "%f" (1.0 +@ 0.5)

A feloldott típus a (+@) mind a kettő (+)(*), mind pedig a típuskövetkezmények felhasználásán alapul, amelyek a statikusan feloldott típusparaméterekre vonatkozó tagkorlátozásokra következtetnek. A feloldott típus az F#-értelmezőben látható módon a következő.

'a -> 'c -> 'd
when ('a or 'b) : (static member ( + ) : 'a * 'b -> 'd) and
('a or 'c) : (static member ( * ) : 'a * 'c -> 'b)

A kimenet a következő.

2
1.500000

Az alábbi példa az SRTP-k használatát mutatja be metódusokkal és statikus módszerekkel:

type Record =
    { Number: int }
    member this.Double() = { Number = this.Number * 2 }
    static member Zero() = { Number = 0 }
    
let inline double<'a when 'a:(member Double: unit -> 'a)> (x: 'a) = x.Double()    
let inline zero<'a when 'a:(static member Zero: unit -> 'a)> () = 'a.Zero()

let r: Record = zero ()
let doubleR = double r

Az F# 7.0-tól kezdve használhatja 'a.Zero() a kényszer megismétlése helyett, ahogy az alábbi példában is látható.

Az F# 4.1-től kezdve konkrét típusneveket is megadhat statikusan feloldott típusparaméter-aláírásokban. A nyelv korábbi verzióiban a típusnevet a fordító tudta kikövetkeztetni, de az aláírásban nem sikerült megadni. Az F# 4.1-es verziójában konkrét típusneveket is megadhat statikusan feloldott típusparaméter-aláírásokban. Íme egy példa (vegye figyelembe, hogy ebben a példában továbbra is használni kell, ^ mert a használat ' egyszerűsítése nem támogatott):

let inline konst x _ = x

type CFunctor() =
    static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a
    static member inline fmap (f: ^a -> ^b, a: ^a option) =
        match a with
        | None -> None
        | Some x -> Some (f x)

    // default implementation of replace
    static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) =
        ((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f))

    // call overridden replace if present
    static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) =
        (^b : (static member replace: ^a * ^b -> ^c) (a, f))

let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) =
        ((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f))

// Note the concrete type 'CFunctor' specified in the signature
let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or  ^b): (static member replace: ^a *  ^b ->  ^a0) =
    replace_instance<CFunctor, _, _, _> (a, f)

Lásd még