Bagikan melalui


Konstruktor

Artikel ini menjelaskan cara menentukan dan menggunakan konstruktor untuk membuat dan menginisialisasi objek kelas dan struktur.

Konstruksi objek kelas

Objek dari jenis kelas memiliki konstruktor. Ada dua jenis konstruktor. Salah satunya adalah konstruktor utama, yang parameternya muncul dalam tanda kurung tepat setelah nama jenis. Anda menentukan konstruktor tambahan opsional lainnya dengan menggunakan kata kunci new. Setiap konstruktor tambahan tersebut harus memanggil konstruktor utama.

Konstruktor utama berisi pengikatan let dan do yang muncul di awal definisi kelas. Pengikatan let mendeklarasikan bidang privat dan metode kelas; pengikatan do menjalankan kode. Untuk informasi selengkapnya tentang pengikatan let di konstruktor kelas, lihat Pengikatan let di Kelas. Untuk informasi selengkapnya tentang pengikatan do dalam konstruktor, lihat Pengikatan do di Kelas.

Terlepas dari apakah konstruktor yang ingin Anda panggil adalah konstruktor utama atau konstruktor tambahan, Anda dapat membuat objek dengan menggunakan ekspresi new, dengan atau tanpa kata kunci new opsional. Anda menginisialisasi objek Anda bersama dengan argumen konstruktor, baik dengan membuat daftar argumen secara berurutan, dipisahkan oleh koma, dan diapit dengan tanda kurung, atau dengan menggunakan argumen dan nilai bernama dalam tanda kurung. Anda juga dapat mengatur properti pada objek selama konstruksi objek dengan menggunakan nama properti dan menetapkan nilai seperti Anda menggunakan argumen konstruktor bernama.

Kode berikut menggambarkan kelas yang memiliki konstruktor dan berbagai cara membuat objek:

// This class has a primary constructor that takes three arguments
// and an additional constructor that calls the primary constructor.
type MyClass(x0, y0, z0) =
    let mutable x = x0
    let mutable y = y0
    let mutable z = z0
    do
        printfn "Initialized object that has coordinates (%d, %d, %d)" x y z
    member this.X with get() = x and set(value) = x <- value
    member this.Y with get() = y and set(value) = y <- value
    member this.Z with get() = z and set(value) = z <- value
    new() = MyClass(0, 0, 0)

// Create by using the new keyword.
let myObject1 = new MyClass(1, 2, 3)
// Create without using the new keyword.
let myObject2 = MyClass(4, 5, 6)
// Create by using named arguments.
let myObject3 = MyClass(x0 = 7, y0 = 8, z0 = 9)
// Create by using the additional constructor.
let myObject4 = MyClass()

Outputnya sebagai berikut:

Initialized object that has coordinates (1, 2, 3)
Initialized object that has coordinates (4, 5, 6)
Initialized object that has coordinates (7, 8, 9)
Initialized object that has coordinates (0, 0, 0)

Konstruksi struktur

Struktur mengikuti semua aturan kelas. Oleh karena itu, Anda dapat memiliki konstruktor utama dan Anda dapat menyediakan konstruktor tambahan dengan menggunakan new. Namun, ada satu perbedaan penting antara struktur dan kelas: struktur dapat memiliki konstruktor tanpa parameter (yaitu, yang tidak memiliki argumen), bahkan jika tidak ada konstruktor utama yang ditentukan. Konstruktor tanpa parameter menginisialisasi semua bidang ke nilai default untuk jenis tersebut, biasanya nol atau yang setara. Setiap konstruktor yang Anda tentukan untuk struktur harus memiliki setidaknya satu argumen, sehingga tidak bertentangan dengan konstruktor tanpa parameter.

Selain itu, struktur sering kali memiliki bidang yang dibuat dengan menggunakan kata kunci val; kelas juga dapat memiliki bidang ini. Struktur dan kelas yang memiliki bidang, yang ditentukan dengan menggunakan kata kunci val juga dapat diinisialisasi dalam konstruktor tambahan dengan menggunakan ekspresi rekaman, seperti yang ditunjukkan dalam kode berikut.

type MyStruct =
    struct
       val X : int
       val Y : int
       val Z : int
       new(x, y, z) = { X = x; Y = y; Z = z }
    end

let myStructure1 = new MyStruct(1, 2, 3)

Untuk informasi selengkapnya, lihat Bidang Eksplisit: Kata Kunci val.

Menjalankan efek samping dalam konstruktor

Sebuah konstruktor utama di sebuah kelas dapat menjalankan kode dalam pengikatan do. Namun, bagaimana jika Anda harus menjalankan kode dalam konstruktor tambahan, tanpa pengikatan do? Untuk melakukannya, Anda menggunakan kata kunci then.

 // Executing side effects in the primary constructor and
// additional constructors.
type Person(nameIn : string, idIn : int) =
    let mutable name = nameIn
    let mutable id = idIn
    do printfn "Created a person object."
    member this.Name with get() = name and set(v) = name <- v
    member this.ID with get() = id and set(v) = id <- v
    new() =
        Person("Invalid Name", -1)
        then
            printfn "Created an invalid person object."

let person1 = new Person("Humberto Acevedo", 123458734)
let person2 = new Person()

Efek samping dari konstruktor utama masih dijalankan. Oleh karena itu, output-nya adalah sebagai berikut:

Created a person object.
Created a person object.
Created an invalid person object.

Alasan mengapa then dibutuhkan ali-alih do lainnya adalah karena kata kunci do memiliki arti standar membatasi ekspresi pengembalian unit ketika ada di isi konstruktor tambahan. Hal tersebut hanya memiliki arti khusus dalam konteks konstruktor utama.

Pengidentifikasi mandiri dalam konstruktor

Di anggota lain, Anda memberikan nama untuk objek saat ini dalam definisi setiap anggota. Anda juga dapat menempatkan pengidentifikasi mandiri pada baris pertama definisi kelas dengan menggunakan kata kunci as segera setelah parameter konstruktor. Contoh berikut menggambarkan sintaks ini.

type MyClass1(x) as this =
    // This use of the self identifier produces a warning - avoid.
    let x1 = this.X
    // This use of the self identifier is acceptable.
    do printfn "Initializing object with X =%d" this.X
    member this.X = x

Dalam konstruktor tambahan, Anda juga dapat menentukan pengidentifikasi mandiri dengan menempatkan klausul as tepat setelah parameter konstruktor. Contoh berikut menggambarkan sintaks ini:

type MyClass2(x : int) =
    member this.X = x
    new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X

Masalah dapat terjadi ketika Anda mencoba untuk menggunakan objek sebelum objek tersebut sepenuhnya ditentukan. Oleh karena itu, penggunaan pengidentifikasi mandiri dapat menyebabkan kompilator mengeluarkan peringatan dan menyisipkan pemeriksaan tambahan untuk memastikan anggota objek tidak diakses sebelum objek tersebut diinisialisasi. Anda hanya boleh menggunakan pengidentifikasi mandiri dalam pengikatan do dari konstruktor utama atau setelah kata kunci then di konstruktor tambahan.

Nama pengidentifikasi mandiri tidak harus this. Namanya dapat berupa pengidentifikasi apa pun yang valid.

Menetapkan nilai ke properti saat inisialisasi

Anda dapat menetapkan nilai ke properti objek kelas dalam kode inisialisasi dengan menambahkan daftar penetapan formulir property = value ke daftar argumen untuk konstruktor. Hal ini ditunjukkan dalam contoh kode berikut:

 type Account() =
    let mutable balance = 0.0
    let mutable number = 0
    let mutable firstName = ""
    let mutable lastName = ""
    member this.AccountNumber
       with get() = number
       and set(value) = number <- value
    member this.FirstName
       with get() = firstName
       and set(value) = firstName <- value
    member this.LastName
       with get() = lastName
       and set(value) = lastName <- value
    member this.Balance
       with get() = balance
       and set(value) = balance <- value
    member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
    member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount


let account1 = new Account(AccountNumber=8782108,
                           FirstName="Darren", LastName="Parker",
                           Balance=1543.33)

Versi kode sebelumnya berikut ini menggambarkan kombinasi argumen biasa, argumen opsional, dan pengaturan properti dalam satu panggilan konstruktor:

type Account(accountNumber : int, ?first: string, ?last: string, ?bal : float) =
   let mutable balance = defaultArg bal 0.0
   let mutable number = accountNumber
   let mutable firstName = defaultArg first ""
   let mutable lastName = defaultArg last ""
   member this.AccountNumber
      with get() = number
      and set(value) = number <- value
   member this.FirstName
      with get() = firstName
      and set(value) = firstName <- value
   member this.LastName
      with get() = lastName
      and set(value) = lastName <- value
   member this.Balance
      with get() = balance
      and set(value) = balance <- value
   member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
   member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount


let account1 = new Account(8782108, bal = 543.33,
                          FirstName="Raman", LastName="Iyer")

Konstruktor di kelas yang diwarisi

Saat mewarisi dari kelas dasar yang memiliki konstruktor, Anda harus menentukan argumennya dalam klausul pewarisan. Untuk informasi selengkapnya, lihat Konstruktor dan warisan.

Konstruktor statis atau konstruktor jenis

Selain menentukan kode untuk membuat objek, pengikatan let dan do statis dapat ditulis dalam jenis kelas yang dijalankan sebelum jenis tersebut digunakan untuk melakukan inisialisasi pada tingkat jenis. Untuk informasi selengkapnya, lihat Pengikatan let di Kelas dan Pengikatan do di Kelas.

Lihat juga