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, yzve 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.

Ayrıca bkz.