Az F# 4.5 újdonságai

Az F# 4.5 több fejlesztést is tartalmaz az F# nyelvhez. Ezek közül a funkciók közül számos össze lett adva, hogy hatékony kódot írjon F# nyelven, miközben a kód biztonságos. Ez azt jelenti, hogy ezeknek a szerkezeteknek a használatakor néhány fogalmat és jelentős mennyiségű fordítóelemzést kell hozzáadnia a nyelvhez.

Első lépések

Az F# 4.5 minden .NET Core-disztribúcióban és Visual Studio-eszközben elérhető. Ismerkedés az F# -tal további információért.

Span és byref-szerű szerkezetek

A Span<T> .NET Core-ban bevezetett típus lehetővé teszi, hogy a memória puffereit erősen gépelt módon képviselje, ami mostantól engedélyezett az F# 4.5-től kezdve. Az alábbi példa bemutatja, hogyan használhatja újra a különböző pufferképekkel rendelkező Span<T> függvényeket:

let safeSum (bytes: Span<byte>) =
    let mutable sum = 0
    for i in 0 .. bytes.Length - 1 do
        sum <- sum + int bytes[i]
    sum

// managed memory
let arrayMemory = Array.zeroCreate<byte>(100)
let arraySpan = new Span<byte>(arrayMemory)

safeSum(arraySpan) |> printfn "res = %d"

// native memory
let nativeMemory = Marshal.AllocHGlobal(100);
let nativeSpan = new Span<byte>(nativeMemory.ToPointer(), 100)

safeSum(nativeSpan) |> printfn "res = %d"
Marshal.FreeHGlobal(nativeMemory)

// stack memory
let mem = NativePtr.stackalloc<byte>(100)
let mem2 = mem |> NativePtr.toVoidPtr
let stackSpan = Span<byte>(mem2, 100)

safeSum(stackSpan) |> printfn "res = %d"

Ennek egyik fontos eleme, hogy a Span és más byref-szerű szerkezetek nagyon merev statikus elemzést végeznek a fordító által, amely korlátozza a használatukat oly módon, hogy váratlannak találja őket. Ez az F# 4.5-ben bevezetett teljesítmény, kifejezőképesség és biztonság közötti alapvető kompromisszum.

Átdolgozott byrefs

Az F# 4.5 előtt az F# byrefs nem volt biztonságos és nem biztonságos számos alkalmazás esetében. Az F# 4.5-ben megoldottuk a byrefs körüli hangképességi problémákat, és ugyanezt a statikus elemzést alkalmaztuk a span és a byref-szerű szerkezetek esetében is.

inref'T<> és outref'T<>

Az írásvédett, írásvédett és írásvédett mutató fogalmának megjelenítéséhez az F# 4.5 bemutatja az inref<'T>outref<'T> írásvédett és írásvédett mutatókat ábrázoló típusokat. Mindegyiknek más szemantikája van. Például nem írhat a következőbe inref<'T>:

let f (dt: inref<DateTime>) =
    dt <- DateTime.Now // ERROR - cannot write to an inref!

A típuskövetkeztetés alapértelmezés szerint a felügyelt mutatókat inref<'T> arra fogja következtetni, hogy azok összhangban vannak az F#-kód nem módosítható jellegével, kivéve, ha valami már deklarálva van. Ha írhatóvá szeretne tenni valamit, deklarálnia kell egy típust, mielőtt mutable a címét egy olyan függvénynek vagy tagnak adja át, amely módosítja azt. További információ: Byrefs.

Olvasható szerkezetek

Az F# 4.5-től kezdődően a következőkkel jegyzetelhet egy szerkezetet IsReadOnlyAttribute :

[<IsReadOnly; Struct>]
type S(count1: int, count2: int) =
    member x.Count1 = count1
    member x.Count2 = count2

Ez nem teszi lehetővé, hogy egy mutable tagot deklaráljon a szerkezetben, és olyan metaadatokat bocsát ki, amelyek lehetővé teszik az F# és a C# számára, hogy a szerelvényből való felhasználáskor olvasva kezelje azt. További információ: ReadOnlystructs.

Üres mutató

A voidptr típus az F# 4.5-ös verzióhoz lesz hozzáadva, ahogy az alábbi függvények is:

  • NativePtr.ofVoidPtr üres mutató natív int mutatóvá alakításához
  • NativePtr.toVoidPtr natív int mutató üres mutatóvá alakításához

Ez akkor hasznos, ha olyan natív összetevővel működik együtt, amely üres mutatókat használ.

A match! kulcsszó

A match! kulcsszó javítja a mintaegyezést egy számítási kifejezésben:

// Code that returns an asynchronous option
let checkBananaAsync (s: string) =
    async {
        if s = "banana" then
            return Some s
        else
            return None
    }

// Now you can use 'match!'
let funcWithString (s: string) =
    async {
        match! checkBananaAsync s with
        | Some bananaString -> printfn "It's banana!"
        | None -> printfn "%s" s
}

Ez lehetővé teszi, hogy lerövidítse a kódot, amely gyakran magában foglalja a beállítások (vagy más típusok) és a számítási kifejezések, például az aszinkron keverését. További információ: egyezés!.

A tömb-, lista- és szekvenciakifejezések egyszerűsített küldési követelményei

Az olyan típusok keverése, amelyek a tömbök, listák és szekvenciális kifejezések egy másiktól öröklődhetnek, hagyományosan megkövetelik, hogy a származtatott típusokat a szülőtípusra :> upcastvagy a . Ez most enyhült, a következőképpen mutatjuk be:

let x0 : obj list  = [ "a" ] // ok pre-F# 4.5
let x1 : obj list  = [ "a"; "b" ] // ok pre-F# 4.5
let x2 : obj list  = [ yield "a" :> obj ] // ok pre-F# 4.5

let x3 : obj list  = [ yield "a" ] // Now ok for F# 4.5, and can replace x2

Behúzási lazítás tömb- és listakifejezésekhez

Az F# 4.5 előtt a tömbök és a listakifejezések túlzott behúzására volt szükség, amikor argumentumként adtuk át a metódushívásoknak. Erre már nincs szükség:

module NoExcessiveIndenting =
    System.Console.WriteLine(format="{0}", arg = [|
        "hello"
    |])
    System.Console.WriteLine([|
        "hello"
    |])