Kayıtlar (F#)
Kayıtlar, isteğe bağlı olarak üyeler ile adlandırılmış değerlerin basit toplamlarını temsil eder. Yapılar veya başvuru türleri olabilir. Bunlar varsayılan olarak başvuru türleridir.
Sözdizimi
[ attributes ]
type [accessibility-modifier] typename =
{ [ mutable ] label1 : type1;
[ mutable ] label2 : type2;
... }
[ member-list ]
Açıklamalar
Önceki söz diziminde, türadı kayıt türünün adıdır, etiket1 ve etiket2, etiketler olarak adlandırılan değerlerin adlarıdır ve tür1 ve tür2 bu değerlerin türleridir. member-list türü için isteğe bağlı üye listesidir. Özniteliğini [<Struct>]
kullanarak başvuru türü olan bir kayıt yerine bir yapı kaydı oluşturabilirsiniz.
Bazı örnekler aşağıda verilmiştir.
// Labels are separated by semicolons when defined on the same line.
type Point = { X: float; Y: float; Z: float }
// You can define labels on their own line with or without a semicolon.
type Customer =
{ First: string
Last: string
SSN: uint32
AccountNumber: uint32 }
// A struct record.
[<Struct>]
type StructPoint = { X: float; Y: float; Z: float }
Her etiket ayrı bir satırda olduğunda, noktalı virgül isteğe bağlıdır.
Kayıt ifadeleri olarak bilinen ifadelerde değerler ayarlayabilirsiniz. Derleyici, türü kullanılan etiketlerden (etiketler diğer kayıt türlerinden yeterince farklıysa) çıkartır. Ayraçlar ({ }), kayıt ifadesini içine alır. Aşağıdaki kod, y
z
ve etiketli x
üç kayan öğe içeren bir kaydı başlatan bir kayıt ifadesini gösterir.
let mypoint = { X = 1.0; Y = 1.0; Z = -1.0 }
Aynı etiketlere sahip başka bir tür varsa kısaltılmış formu kullanmayın.
type Point = { X: float; Y: float; Z: float }
type Point3D = { X: float; Y: float; Z: float }
// Ambiguity: Point or Point3D?
let mypoint3D = { X = 1.0; Y = 1.0; Z = 0.0 }
En son bildirilen türün etiketleri, önceden bildirilen türe göre önceliklidir, bu nedenle önceki örnekte mypoint3D
olduğu çıkarılır Point3D
. Aşağıdaki kodda olduğu gibi kayıt türünü açıkça belirtebilirsiniz.
let myPoint1 = { Point.X = 1.0; Y = 1.0; Z = 0.0 }
Yöntemler, aynı sınıf türleri için olduğu gibi kayıt türleri için de tanımlanabilir.
Kayıt İfadelerini Kullanarak Kayıt Oluşturma
Kayıtta tanımlanan etiketleri kullanarak kayıtları başlatabilirsiniz. Bunu sağlayan bir ifade, kayıt ifadesi olarak adlandırılır. Kayıt ifadesini içine almak için ayraçları kullanın ve sınırlayıcı olarak noktalı virgül kullanın.
Aşağıdaki örnekte bir kaydın nasıl oluşturulacağı gösterilmektedir.
type MyRecord = { X: int; Y: int; Z: int }
let myRecord1 = { X = 1; Y = 2; Z = 3 }
Kayıt ifadesindeki ve tür tanımındaki son alandan sonraki noktalı virgüller, alanların tümünün tek satırda olup olmadığına bakılmaksızın isteğe bağlıdır.
Kayıt oluşturduğunuzda, her alan için değer sağlamanız gerekir. Herhangi bir alan için başlatma ifadesindeki diğer alanların değerlerine başvuramazsınız.
Aşağıdaki kodda, türü myRecord2
alanların adlarından çıkarılır. İsteğe bağlı olarak, tür adını açıkça belirtebilirsiniz.
let myRecord2 =
{ MyRecord.X = 1
MyRecord.Y = 2
MyRecord.Z = 3 }
Var olan bir kaydı kopyalamanız ve alan değerlerinden bazılarını değiştirmeniz gerektiğinde başka bir kayıt oluşturma biçimi yararlı olabilir. Aşağıdaki kod satırı bunu gösterir.
let myRecord3 = { myRecord2 with Y = 100; Z = 2 }
Kayıt ifadesinin bu biçimine kayıt kopyalama ve güncelleştirme ifadesi adı verilir.
Kayıtlar varsayılan olarak sabittir; ancak, bir kopyalama ve güncelleştirme ifadesi kullanarak değiştirilmiş kayıtları kolayca oluşturabilirsiniz. Ayrıca, açık bir şekilde değiştirilebilir bir alan belirtebilirsiniz.
type Car =
{ Make: string
Model: string
mutable Odometer: int }
let myCar =
{ Make = "Fabrikam"
Model = "Coupe"
Odometer = 108112 }
myCar.Odometer <- myCar.Odometer + 21
DefaultValue özniteliğini kayıt alanlarıyla kullanmayın. Daha iyi bir yaklaşım, varsayılan değerlerle başlatılan alanlara sahip kayıtların varsayılan örneklerini tanımlamak ve ardından varsayılan değerlerden farklı alanları ayarlamak için kayıt ifadesini kopyalayıp güncelleştirmektir.
// Rather than use [<DefaultValue>], define a default record.
type MyRecord =
{ Field1 : int
Field2 : int }
let defaultRecord1 = { Field1 = 0; Field2 = 0 }
let defaultRecord2 = { Field1 = 1; Field2 = 25 }
// Use the with keyword to populate only a few chosen fields
// and leave the rest with default values.
let rr3 = { defaultRecord1 with Field2 = 42 }
Karşılıklı Özyinelemeli Kayıtlar Oluşturma
Bir kayıt oluştururken, daha sonra tanımlamak istediğiniz başka bir türe bağlı olmasını isteyebilirsiniz. Bu, karşılıklı özyinelemeli olacak kayıt türlerini tanımlamadığınız sürece bir derleme hatasıdır.
Karşılıklı özyinelemeli kayıtların tanımlanması anahtar sözcüğüyle and
gerçekleştirilir. Bu, 2 veya daha fazla kayıt türünü birbirine bağlamanızı sağlar.
Örneğin, aşağıdaki kod bir Person
ve Address
türünü karşılıklı özyinelemeli olarak tanımlar:
// Create a Person type and use the Address type that is not defined
type Person =
{ Name: string
Age: int
Address: Address }
// Define the Address type which is used in the Person record
and Address =
{ Line1: string
Line2: string
PostCode: string
Occupant: Person }
Her ikisinin de örneklerini oluşturmak için aşağıdakileri yaparsınız:
// Create a Person type and use the Address type that is not defined
let rec person =
{
Name = "Person name"
Age = 12
Address =
{
Line1 = "line 1"
Line2 = "line 2"
PostCode = "abc123"
Occupant = person
}
}
Önceki örneği anahtar sözcüğü olmadan and
tanımlarsanız, derlenmez. Anahtar and
sözcük, karşılıklı özyinelemeli tanımlar için gereklidir.
Kayıtlarla Desen Eşleştirme
Kayıtlar desen eşleştirme ile kullanılabilir. Bazı alanları açıkça belirtebilir ve bir eşleşme gerçekleştiğinde atanacak diğer alanlar için değişkenler sağlayabilirsiniz. Aşağıdaki kod örneği bunu gösterir.
type Point3D = { X: float; Y: float; Z: float }
let evaluatePoint (point: Point3D) =
match point with
| { X = 0.0; Y = 0.0; Z = 0.0 } -> printfn "Point is at the origin."
| { X = xVal; Y = 0.0; Z = 0.0 } -> printfn "Point is on the x-axis. Value is %f." xVal
| { X = 0.0; Y = yVal; Z = 0.0 } -> printfn "Point is on the y-axis. Value is %f." yVal
| { X = 0.0; Y = 0.0; Z = zVal } -> printfn "Point is on the z-axis. Value is %f." zVal
| { X = xVal; Y = yVal; Z = zVal } -> printfn "Point is at (%f, %f, %f)." xVal yVal zVal
evaluatePoint { X = 0.0; Y = 0.0; Z = 0.0 }
evaluatePoint { X = 100.0; Y = 0.0; Z = 0.0 }
evaluatePoint { X = 10.0; Y = 0.0; Z = -1.0 }
Bu kodun çıkışı aşağıdaki gibidir.
Point is at the origin.
Point is on the x-axis. Value is 100.000000.
Point is at (10.000000, 0.000000, -1.000000).
Kayıtlar ve üyeler
Kayıtlarda sınıflarla yaptığınız gibi üyeleri belirtebilirsiniz. Alanlar için destek yoktur. Yaygın bir yaklaşım, kolay kayıt oluşturma için statik üye Default
tanımlamaktır:
type Person =
{ Name: string
Age: int
Address: string }
static member Default =
{ Name = "Phillip"
Age = 12
Address = "123 happy fun street" }
let defaultPerson = Person.Default
Bir kendi tanımlayıcısı kullanırsanız, bu tanımlayıcı üyesi çağrılan kaydın örneğine başvurur:
type Person =
{ Name: string
Age: int
Address: string }
member this.WeirdToString() =
this.Name + this.Address + string this.Age
let p = { Name = "a"; Age = 12; Address = "abc123" }
let weirdString = p.WeirdToString()
Kayıtlar ve Sınıflar Arasındaki Farklar
Kayıt alanları, otomatik olarak özellik olarak kullanıma sunulan ve kayıtların oluşturulması ve kopyalanmasında kullanılan sınıf alanlarından farklıdır. Kayıt inşaatı da sınıf yapımından farklıdır. Kayıt türünde bir oluşturucu tanımlayamazsınız. Bunun yerine, bu konuda açıklanan yapı söz dizimi geçerlidir. Sınıfların oluşturucu parametreleri, alanları ve özellikleri arasında doğrudan bir ilişkisi yoktur.
Birleşim ve yapı türleri gibi kayıtların da yapısal eşitlik semantiği vardır. Sınıflar başvuru eşitliği semantiğine sahiptir. Aşağıdaki kod örneği bunu gösterir.
type RecordTest = { X: int; Y: int }
let record1 = { X = 1; Y = 2 }
let record2 = { X = 1; Y = 2 }
if (record1 = record2) then
printfn "The records are equal."
else
printfn "The records are unequal."
Bu kodun çıkışı aşağıdaki gibidir:
The records are equal.
Sınıflarla aynı kodu yazarsanız, iki değer yığındaki iki nesneyi temsil ettiğinden ve yalnızca adresler karşılaştırılacağından (sınıf türü yöntemi geçersiz kılmadığı System.Object.Equals
sürece) iki sınıf nesnesi eşit olmaz.
Kayıtlar için başvuru eşitliğine ihtiyacınız varsa, özniteliği [<ReferenceEquality>]
kaydın üstüne ekleyin.