Bidang Eksplisit: Kata Kunci val
Kata kunci val
digunakan untuk mendeklarasikan lokasi untuk menyimpan nilai dalam jenis kelas atau struktur, tanpa menginsialisasinya. Lokasi penyimpanan yang dideklarasikan dengan cara ini disebut bidang eksplisit. Penggunaan lain dari val
kata kunci adalah bersama dengan member
kata kunci untuk mendeklarasikan properti yang diimplementasikan secara otomatis. Untuk informasi selengkapnya tentang properti yang diterapkan secara otomatis, lihat Properti.
Sintaks
val [ mutable ] [ access-modifier ] field-name : type-name
Keterangan
Cara biasa untuk menentukan bidang dalam kelas atau jenis struktur adalah dengan menggunakan pengikatan let
. Namun, pengikatan let
harus diinisialisasi sebagai bagian dari konstruktor kelas, yang tidak selalu mungkin, diperlukan, atau diinginkan. Anda bisa menggunakan kata kunci val
saat Anda menginginkan bidang yang tidak diinisialisasi.
Bidang eksplisit dapat statis atau non-statis. Pengubah akses dapat berupa public
, private
, atau internal
. Secara default, bidang eksplisit bersifat publik. Hal ini berbeda dengan pengikatan let
di kelas, yang selalu bersifat privat.
Atribut DefaultValue diperlukan pada bidang eksplisit dalam jenis kelas yang memiliki konstruktor utama. Atribut ini menentukan bahwa bidang diinsialisasi menjadi nol. Jenis bidang harus mendukung inisialisasi nol. Jenis mendukung inisialisasi nol jika salah satu dari yang berikut:
- Jenis primitif yang memiliki nilai nol.
- Jenis yang mendukung nilai nol, baik sebagai nilai normal, sebagai nilai abnormal, atau sebagai representasi nilai. Hal ini termasuk kelas, tuple, catatan, fungsi, antarmuka, jenis referensi .NET, jenis
unit
, dan jenis gabungan yang diskriminasi. - Jenis nilai .NET.
- Struktur yang semua bidangnya mendukung nilai nol default.
Misalnya, bidang yang tidak dapat diubah yang disebut someField
memiliki bidang dukungan di representasi yang dikompilasi .NET dengan nama someField@
, dan Anda mengakses nilai yang disimpan menggunakan properti bernama someField
.
Untuk bidang yang dapat berubah, representasi yang dikompilasi .NET adalah bidang .NET.
Peringatan
Namespace .NET Framework System.ComponentModel
berisi atribut yang memiliki nama yang sama. Untuk informasi tentang atribut ini, lihat DefaultValueAttribute.
Kode berikut menunjukkan penggunaan bidang eksplisit dan, untuk perbandingan, pengikatan let
di kelas yang memiliki konstruktor utama. Perhatikan bahwa bidang myInt1
yang terikat let
bersifat privat. Ketika bidang myInt1
yang terikat let
dirujuk dari metode anggota, pengidentifikasi this
mandiri tidak diperlukan. Tetapi ketika Anda mereferensikan bidang myInt2
dan myString
eksplisit, pengidentifikasi mandiri diperlukan.
type MyType() =
let mutable myInt1 = 10
[<DefaultValue>] val mutable myInt2 : int
[<DefaultValue>] val mutable myString : string
member this.SetValsAndPrint( i: int, str: string) =
myInt1 <- i
this.myInt2 <- i + 1
this.myString <- str
printfn "%d %d %s" myInt1 (this.myInt2) (this.myString)
let myObject = new MyType()
myObject.SetValsAndPrint(11, "abc")
// The following line is not allowed because let bindings are private.
// myObject.myInt1 <- 20
myObject.myInt2 <- 30
myObject.myString <- "def"
printfn "%d %s" (myObject.myInt2) (myObject.myString)
Outputnya sebagai berikut:
11 12 abc
30 def
Kode berikut menunjukkan penggunaan bidang eksplisit dalam kelas yang tidak memiliki konstruktor utama. Dalam hal ini, atribut DefaultValue
tidak diperlukan, tetapi semua bidang harus diinisialisasi dalam konstruktor yang ditentukan untuk jenis tersebut.
type MyClass =
val a : int
val b : int
// The following version of the constructor is an error
// because b is not initialized.
// new (a0, b0) = { a = a0; }
// The following version is acceptable because all fields are initialized.
new(a0, b0) = { a = a0; b = b0; }
let myClassObj = new MyClass(35, 22)
printfn "%d %d" (myClassObj.a) (myClassObj.b)
Outputnya adalah 35 22
.
Kode berikut menunjukkan penggunaan bidang eksplisit dalam struktur. Karena struktur adalah jenis nilai, struktur secara otomatis memiliki konstruktor tanpa parameter yang menetapkan nilai bidangnya menjadi nol. Oleh karena itu, atribut DefaultValue
tidak diperlukan.
type MyStruct =
struct
val mutable myInt : int
val mutable myString : string
end
let mutable myStructObj = new MyStruct()
myStructObj.myInt <- 11
myStructObj.myString <- "xyz"
printfn "%d %s" (myStructObj.myInt) (myStructObj.myString)
Outputnya adalah 11 xyz
.
Berhati-hatilah, jika Anda akan menginisialisasi struktur Anda dengan bidang mutable
tanpa kata kundi mutable
, tugas Anda akan bekerja pada salinan struktur yang akan dibuang tepat setelah penugasan. Oleh karena itu struktur Anda tidak akan berubah.
[<Struct>]
type Foo =
val mutable bar: string
member self.ChangeBar bar = self.bar <- bar
new (bar) = {bar = bar}
let foo = Foo "1"
foo.ChangeBar "2" //make implicit copy of Foo, changes the copy, discards the copy, foo remains unchanged
printfn "%s" foo.bar //prints 1
let mutable foo' = Foo "1"
foo'.ChangeBar "2" //changes foo'
printfn "%s" foo'.bar //prints 2
Bidang eksplisit tidak dimaksudkan untuk penggunaan rutin. Secara umum, jika memungkinkan Anda harus menggunakan pengikatan let
di kelas, bukan bidang eksplisit. Bidang eksplisit berguna dalam skenario interoperabilitas tertentu, seperti ketika Anda perlu menentukan struktur yang akan digunakan dalam panggilan platform ke API asli, atau dalam skenario interop COM. Untuk informasi selengkapnya, lihat Fungsi Eksternal. Situasi lain di mana bidang eksplisit mungkin diperlukan adalah ketika Anda bekerja dengan generator kode F # yang memancarkan kelas tanpa konstruktor utama. Bidang eksplisit juga berguna untuk variabel thread-statis atau konstruksi serupa. Untuk informasi selengkapnya, lihat System.ThreadStaticAttribute
.
Ketika kata kunci member val
muncul bersama-sama dalam definisi jenis, itu adalah definisi dari properti yang diimplementasikan secara otomatis. Untuk informasi selengkapnya, lihat Properti.