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 public
adlandı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 float
iki 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 prism
olduğ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 Some
None
olan ayrımcı bir birleşim olduğunu belirtir. Büyük Some
/küçük harf, türü tür parametresiyle 'a
temsil 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ı option
da 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 Some
option
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:
- Bunlar değer türü olarak kopyalanır ve değer türü semantiğine sahiptir.
- Çok harfli yapısı Ayrımcı Birleşim ile özyinelemeli tür tanımı kullanamazsınız.
- Ç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, Node
tamsayı değeri ve sol ve sağ alt ağaç içeren bir düğüm olan ve Tip
ağ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 myTree
ağaç yapısı gösterilmektedir.
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>]