Ayrılmış Birleşimler

Ayrımcı birleşimler, büyük olasılıkla her biri farklı değerlere ve türlere sahip bir dizi adlandırılmış durumdan biri olabilecek değerler için destek sağlar. Ayrımcı birleşimler heterojen veriler için yararlıdır; geçerli ve hata durumları dahil olmak üzere özel durumlara sahip olabilecek veriler; bir örnekten diğerine türe göre değişen veriler; ve küçük nesne hiyerarşileri için bir alternatif olarak. Ayrıca, özyinelemeli ayrımcı birleşimler ağaç veri yapılarını temsil etmek için kullanılır.

Sözdizimi

[ attributes ]
type [accessibility-modifier] type-name =
    | case-identifier1 [of [ fieldname1 : ] type1 [ * [ fieldname2 : ] type2 ...]
    | case-identifier2 [of [fieldname3 : ]type3 [ * [ fieldname4 : ]type4 ...]

    [ member-list ]

Açıklamalar

Ayrımcı birleşimler diğer dillerdeki birleşim türlerine benzer, ancak farklılıklar vardır. C++ içindeki birleşim türünde veya Visual Basic'te değişken türünde olduğu gibi, değerde depolanan veriler sabit değildir; çeşitli seçeneklerden biri olabilir. Ancak, bu diğer dillerdeki birleşimlerden farklı olarak, olası seçeneklerin her birine bir servis talebi tanımlayıcısı verilir. Büyük/küçük harf tanımlayıcıları, bu türdeki nesnelerin olabileceği çeşitli olası değer türlerinin adlarıdır; değerler isteğe bağlıdır. Değerler yoksa, büyük/küçük harf bir numaralandırma olayına eşdeğerdir. Değerler varsa, her değer belirtilen türde tek bir değer veya aynı veya farklı türlerdeki birden çok alanı toplayan bir tanımlama grubu olabilir. Tek bir alana bir ad verebilirsiniz, ancak aynı durumdaki diğer alanlar adlandırılmış olsa bile ad isteğe bağlıdır.

Ayrımcı birleşimler için erişilebilirlik varsayılan olarak olarak publicadlandırılır.

Örneğin, bir Şekil türünün aşağıdaki bildirimini göz önünde bulundurun.

type Shape =
    | Rectangle of width : float * length : float
    | Circle of radius : float
    | Prism of width : float * float * height : float

Yukarıdaki kod, üç durumdan herhangi birinin değerine sahip olabilecek ayrımcı birleşim Şeklini bildirir: Dikdörtgen, Daire ve Prizma. Her servis talebinin farklı bir alan kümesi vardır. Rectangle büyük/küçük harf, adların genişliği ve uzunluğuna sahip her ikisi de türünde floatiki adlandırılmış alana sahiptir. Circle olayının radius adlı tek bir alanı vardır. Prism örneğinde ikisi (genişlik ve yükseklik) olarak adlandırılan üç alan vardır. Adsız alanlar anonim alanlar olarak adlandırılır.

Adlandırılmış ve anonim alanlar için aşağıdaki örneklere göre değerler sağlayarak nesneleri oluşturursunuz.

let rect = Rectangle(length = 1.3, width = 10.0)
let circ = Circle (1.0)
let prism = Prism(5., 2.0, height = 3.0)

Bu kod, başlatmada adlandırılmış alanları kullanabileceğinizi veya bildirimdeki alanların sıralamasına güvenebileceğinizi ve her alanın değerlerini sırayla sağlayabileceğinizi gösterir. Önceki koddaki oluşturucu rect çağrısı adlandırılmış alanları kullanır, ancak oluşturucu circ çağrısı sıralamayı kullanır. sıralı alanları ve adlandırılmış alanları, yapısında prismolduğu gibi karıştırabilirsiniz.

Türü option , F# çekirdek kitaplığındaki basit bir ayrımcı birleşimdir. Türü option aşağıdaki gibi bildirilir.

// The option type is a discriminated union.
type Option<'a> =
    | Some of 'a
    | None

Önceki kod, türünün Option ve olmak üzere iki örneği SomeNoneolan ayrımcı bir birleşim olduğunu belirtir. Büyük Some /küçük harf, türü tür parametresiyle 'atemsil edilen bir anonim alandan oluşan ilişkili bir değere sahiptir. Büyük None /küçük harf ilişkili bir değere sahip değil. Bu nedenle tür option , bir tür değerine sahip olan veya değer içermeyen genel bir tür belirtir. Option Türün daha yaygın olarak kullanılan küçük harfli bir diğer adı optionda vardır.

Servis talebi tanımlayıcıları, ayrımcı birleşim türü için oluşturucu olarak kullanılabilir. Örneğin, türündeki değerleri option oluşturmak için aşağıdaki kod kullanılır.

let myOption1 = Some(10.0)
let myOption2 = Some("string")
let myOption3 = None

Büyük/küçük harf tanımlayıcıları desen eşleştirme ifadelerinde de kullanılır. Desen eşleştirme ifadesinde, tek tek servis talepleri ile ilişkili değerler için tanımlayıcılar sağlanır. Örneğin, aşağıdaki kodda, x türün büyük/küçük harfle Someoption ilişkili değeri verilen tanımlayıcıdır.

let printValue opt =
    match opt with
    | Some x -> printfn "%A" x
    | None -> printfn "No value."

Desen eşleştirme ifadelerinde, ayrımcı birleşim eşleşmelerini belirtmek için adlandırılmış alanları kullanabilirsiniz. Daha önce bildirilen Şekil türü için, aşağıdaki kodda gösterildiği gibi adlandırılmış alanları kullanarak alanların değerlerini ayıklayabilirsiniz.

let getShapeWidth shape =
    match shape with
    | Rectangle(width = w) -> w
    | Circle(radius = r) -> 2. * r
    | Prism(width = w) -> w

Normalde, servis talebi tanımlayıcıları birleşim adıyla nitelemeden kullanılabilir. Adın her zaman birleşim adıyla nitelenmiş olmasını istiyorsanız, birleşim türü tanımına RequireQualifiedAccess özniteliğini uygulayabilirsiniz.

Ayrımcı Birleşimleri Açma

F# 'de Ayrımcı Birleşimler genellikle etki alanı modellemesinde tek bir türü sarmalamada kullanılır. Desen eşleştirmesi aracılığıyla temel alınan değeri ayıklamak da kolaydır. Tek bir olay için eşleşme ifadesi kullanmanız gerekmez:

let ([UnionCaseIdentifier] [values]) = [UnionValue]

Aşağıdaki örnek bunu gösterir:

type ShaderProgram = | ShaderProgram of id:int

let someFunctionUsingShaderProgram shaderProgram =
    let (ShaderProgram id) = shaderProgram
    // Use the unwrapped value
    ...

Desen eşleştirmeye doğrudan işlev parametrelerinde de izin verilir, böylece burada tek bir büyük/küçük harf çıkarabilirsiniz:

let someFunctionUsingShaderProgram (ShaderProgram id) =
    // Use the unwrapped value
    ...

Ayrımcı Yapı Birleşimleri

Ayrıca, Ayrımcı Birleşimleri yapılar olarak da temsil edebilirsiniz. Bu işlem özniteliğiyle [<Struct>] yapılır.

[<Struct>]
type SingleCase = Case of string

[<Struct>]
type Multicase =
    | Case1 of Case1 : string
    | Case2 of Case2 : int
    | Case3 of Case3 : double

Bunlar başvuru türleri değil değer türleri olduğundan, başvuru ayrımcı birleşimleriyle karşılaştırıldığında dikkat edilmesi gereken ek noktalar vardır:

  1. Bunlar değer türü olarak kopyalanır ve değer türü semantiğine sahiptir.
  2. Çok harfli yapısı Ayrımcı Birleşim ile özyinelemeli tür tanımı kullanamazsınız.
  3. Çok harfli yapı Ayrımcı Birleşim için benzersiz büyük/küçük harf adları sağlamanız gerekir.

Nesne Hiyerarşileri Yerine Ayrımcı Birleşimler Kullanma

Küçük bir nesne hiyerarşisine daha basit bir alternatif olarak genellikle ayrımcı bir birleşim kullanabilirsiniz. Örneğin, daire, kare vb. türleri türetilmiş bir Shape temel sınıf yerine aşağıdaki ayrımcı birleşim kullanılabilir.

type Shape =
    // The value here is the radius.
    | Circle of float
    // The value here is the side length.
    | EquilateralTriangle of double
    // The value here is the side length.
    | Square of double
    // The values here are the height and width.
    | Rectangle of double * double

Nesne odaklı bir uygulamada kullandığınız gibi, bir alanı veya çevreyi hesaplamak için sanal bir yöntem yerine, bu miktarları hesaplamak için uygun formüllerle dallanan desen eşleştirmeyi kullanabilirsiniz. Aşağıdaki örnekte, şekle bağlı olarak alanı hesaplamak için farklı formüller kullanılmıştır.

let pi = 3.141592654

let area myShape =
    match myShape with
    | Circle radius -> pi * radius * radius
    | EquilateralTriangle s -> (sqrt 3.0) / 4.0 * s * s
    | Square s -> s * s
    | Rectangle(h, w) -> h * w

let radius = 15.0
let myCircle = Circle(radius)
printfn "Area of circle that has radius %f: %f" radius (area myCircle)

let squareSide = 10.0
let mySquare = Square(squareSide)
printfn "Area of square that has side %f: %f" squareSide (area mySquare)

let height, width = 5.0, 10.0
let myRectangle = Rectangle(height, width)
printfn "Area of rectangle that has height %f and width %f is %f" height width (area myRectangle)

Çıktı aşağıdaki şekilde olacaktır:

Area of circle that has radius 15.000000: 706.858347
Area of square that has side 10.000000: 100.000000
Area of rectangle that has height 5.000000 and width 10.000000 is 50.000000

Ağaç Veri Yapıları için Ayrımcı Birleşimler Kullanma

Ayrımcı birleşimler özyinelemeli olabilir, yani birleşimin kendisi bir veya daha fazla durum türüne dahil edilebilir. Özyinelemeli ayrımcı birleşimler, programlama dillerindeki ifadeleri modellemek için kullanılan ağaç yapıları oluşturmak için kullanılabilir. Aşağıdaki kodda, ikili ağaç veri yapısı oluşturmak için özyinelemeli ayrımcı bir birleşim kullanılır. Birleşim, Nodetamsayı değeri ve sol ve sağ alt ağaç içeren bir düğüm olan ve Tipağacı sonlandıran iki durumdan oluşur.

type Tree =
    | Tip
    | Node of int * Tree * Tree

let rec sumTree tree =
    match tree with
    | Tip -> 0
    | Node(value, left, right) -> value + sumTree (left) + sumTree (right)

let myTree =
    Node(0, Node(1, Node(2, Tip, Tip), Node(3, Tip, Tip)), Node(4, Tip, Tip))

let resultSumTree = sumTree myTree

Önceki kodda resultSumTree değeri 10'dır. Aşağıdaki çizimde için myTreeağaç yapısı gösterilmektedir.

Diagram that shows the tree structure for myTree.

Ağaçtaki düğümler heterojense ayrımcı birleşimler iyi çalışır. Aşağıdaki kodda türü Expression , sayıların ve değişkenlerin eklenmesini ve çoğaltıldığını destekleyen basit bir programlama dilinde bir ifadenin soyut söz dizimi ağacını temsil eder. Birleşim durumlarından bazıları özyinelemeli değildir ve sayıları (Number) veya değişkenleri (Variable ) temsil eder. Diğer durumlar özyinelemeli olup, işlenenlerin de ifade olduğu işlemleri (Add ve Multiply) temsil eder. İşlev, Evaluate söz dizimi ağacını özyinelemeli olarak işlemek için bir eşleşme ifadesi kullanır.

type Expression =
    | Number of int
    | Add of Expression * Expression
    | Multiply of Expression * Expression
    | Variable of string

let rec Evaluate (env: Map<string, int>) exp =
    match exp with
    | Number n -> n
    | Add(x, y) -> Evaluate env x + Evaluate env y
    | Multiply(x, y) -> Evaluate env x * Evaluate env y
    | Variable id -> env[id]

let environment = Map [ "a", 1; "b", 2; "c", 3 ]

// Create an expression tree that represents
// the expression: a + 2 * b.
let expressionTree1 = Add(Variable "a", Multiply(Number 2, Variable "b"))

// Evaluate the expression a + 2 * b, given the
// table of values for the variables.
let result = Evaluate environment expressionTree1

Bu kod yürütürken değeri result 5'tir.

Üyeler

Ayrımcı birleşimlerde üye tanımlamak mümkündür. Aşağıdaki örnekte bir özelliği tanımlama ve arabirim uygulama gösterilmektedir:

open System

type IPrintable =
    abstract Print: unit -> unit

type Shape =
    | Circle of float
    | EquilateralTriangle of float
    | Square of float
    | Rectangle of float * float

    member this.Area =
        match this with
        | Circle r -> Math.PI * (r ** 2.0)
        | EquilateralTriangle s -> s * s * sqrt 3.0 / 4.0
        | Square s -> s * s
        | Rectangle(l, w) -> l * w

    interface IPrintable with
        member this.Print () =
            match this with
            | Circle r -> printfn $"Circle with radius %f{r}"
            | EquilateralTriangle s -> printfn $"Equilateral Triangle of side %f{s}"
            | Square s -> printfn $"Square with side %f{s}"
            | Rectangle(l, w) -> printfn $"Rectangle with length %f{l} and width %f{w}"

Ortak öznitelikler

Aşağıdaki öznitelikler yaygın olarak ayrımcı birleşimlerde görülür:

  • [<RequireQualifiedAccess>]
  • [<NoEquality>]
  • [<NoComparison>]
  • [<Struct>]

Ayrıca bkz.