F # 9: Opsi Opsi

Jika C # memiliki konsep nol untuk tipe referensi dan Nullabe untuk struktur. Ini dapat mengambil salah satu dari 2 bentuk berikut (untuk demonstrasi, saya menggunakan tipe int di sini, tetapi jenisnya dapat berupa struktur apa pun).

  • Tidak dapat dibatalkan
  • int?

Penafian
   Nullabe  Nullable<T> ,    - ,    


Keduanya setara.

Kelas Nullable menyediakan beberapa properti pembantu dan metode yang membuatnya mudah untuk bekerja dengan tipe dan struktur nol. Ini adalah sebagai berikut:

  • Memiliki nilai
  • Nilai
  • GetValueOrDefault ()
  • GetValueOrDefault (T)

Ada sesuatu yang sedikit berbeda dari F # dalam bentuk jenis Opsi , yang merupakan jenis yang lebih ramah F # yang lebih suka tidak berurusan dengan nol, tetapi lebih suka berurusan dengan hal-hal dalam hal "Dapat berisi nilai jenis" atau "Mungkin tidak memiliki nilai. " Kedengarannya seperti Nullable, tetapi pada akhirnya tipe F #, jadi Anda dapat mengharapkannya digunakan secara normal dalam hal-hal F #.

Hal lain yang perlu diperhatikan dengan tipe Opsi F # adalah dapat digunakan untuk jenis apa pun, bukan hanya struktur. Ini berbeda dari .NET Nullable, yang hanya dapat digunakan dengan struktur.

Nilai Tidak ada digunakan ketika tidak ada nilai; jika tidak, ekspresi Some (...) memberikan nilai. Nilai Some and None dapat digunakan saat mencocokkan dengan pola, contoh yang akan kita lihat di posting ini.

Seperti Nullable, tipe F # Option memiliki beberapa properti / metode pembantu, yang ditunjukkan pada tabel di bawah ini.

Tidak ada
Pilihan T
Properti statis yang memungkinkan Anda membuat nilai parameter dengan nilai Tidak Ada.
Isnone
bool
Mengembalikan nilai true jika parameternya adalah Tidak ada.
Masalah
bool
Mengembalikan nilai true jika parameter memiliki nilai selain Tidak Ada.
Beberapa
Pilihan T
Anggota statis yang membuat parameter yang nilainya bukan Tidak ada.
Nilai
'T
Mengembalikan nilai dasar atau melempar NullReferenceException jika nilainya Tidak Ada.

Membuat Opsi


Jadi, sekarang kita tahu apa jenis Opsi, bagaimana kita membuatnya. Mari kita lihat beberapa contoh. Perhatikan bahwa dalam contoh ini, saya menggunakan metode pembantu IsSome / IsNone. Secara pribadi, saya percaya bahwa membandingkan dengan sampel adalah cara terbaik, karena ini akan membantu Anda membandingkan semua kasus, termasuk opsi Tidak.

Sebenarnya, saya akan menunjukkan kepada Anda betapa mudahnya untuk mendapatkan sesuatu yang salah ketika Anda bekerja dengan jenis Opsi jika Anda memutuskan untuk menggunakan metode pembantu, tetapi pertama-tama mari kita lihat contoh case yang tepat.

 let someInt = Some(43) let someString = Some("cat") let printTheOption (opt :Option<'a>) = printfn "Actual Option=%A" opt printfn "IsNone=%b, IsSome=%b Value=%A\r\n\r\n" opt.IsNone opt.IsSome opt.Value printfn "let someInt = Some(43)" printfn "let someString = Some(\"cat\")" printfn "printTheOption (someInt)" printTheOption someInt printfn "printTheOption (someString)" printTheOption someString 

gambar

Tetapi bagaimana jika kita mencobanya lagi menggunakan kode ini, di mana kita tidak memiliki nilai Option, yang akan kita sampaikan ke fungsi printTheOption:

 let demoNone = None let printTheOption (opt :Option<'a>) = printfn "Actual Option=%A" opt printfn "IsNone=%b, IsSome=%b Value=%A\r\n\r\n" opt.IsNone opt.IsSome opt.Value printfn "let demoNone = None" printfn "printTheOption demoNone" printTheOption demoNone 

gambar

Seperti yang Anda lihat, kami punya masalah di sini. Masalahnya adalah bahwa kami mencoba untuk mendapatkan nilai Opsi menggunakan properti.Nilai pembantu, dalam hal ini Tidak ada, jadi kami mendapat NullReferenceException. Terlihat pada tabel di atas bahwa ketika Anda menggunakan properti dan metode bantu, Anda bisa mendapatkan pengecualian. Nah, Anda bisa menggunakan metode IsNone dan Anda akan selalu memeriksa nilainya menggunakan ini ketika Anda bisa menggunakan pencocokan pola bersih yang bagus.

Jika Anda tidak dapat menerima ini, tanyakan pada diri sendiri berapa kali Anda harus memeriksa nilai nol ketika menggunakan C #. Ini bahkan membuat orang memasukkan konstruksi fungsional, seperti Maybe Null Monad, dalam kode .NET biasa.

Jadi, sekarang kita telah melihat bahaya menggunakan metode / properti pembantu, sekarang mari kita perhatikan bagaimana kita dapat menghindari pengecualian ini:

 et printTheOption (opt :Option<'a>) = match opt with | Some a -> printfn "opt is Some, and has value %A" a | None -> printfn "opt is None" let demoNone = None let someInt = Some 1 let someString = Some "crazy dude in the monkey house" printTheOption demoNone printTheOption someInt printTheOption someString 

Pendapat pribadi saya adalah bahwa itu lebih mudah dibaca daripada kode yang akan dihiasi dengan IsSome / IsNone di mana-mana. Ini, tentu saja, adalah urusan semua orang, tetapi kenyataan bahwa kami telah membahas semua dasar-dasar di sini dalam fungsi sederhana ini tidak dapat diabaikan.

gambar

Opsi vs Null


Jadi, kami berbicara tentang Opsi dalam F # dibandingkan dengan Nullabe, dan kami tahu bahwa jenis Opsi dapat digunakan dengan jenis apa pun, sementara Nullable hanya dapat digunakan dengan struktur. Tapi bagaimana dengan tipe Opsi dibandingkan dengan tipe referensi reguler di .NET. Nah, satu kemenangan besar untuk Opsi adalah ketika Anda menggunakan jenis referensi di .NET, Anda berurusan dengan referensi penunjuk, yang karenanya dapat diatur ke nol. Namun, jenis objek tetap sama seperti yang dideklarasikan, yang mungkin berisi referensi yang valid ke objek di heap (Heap) atau mungkin nol.

Adalah normal untuk menulis seperti ini:

 string s1 = "cats"; int s1Length = s1.Length; string s2 = null; int s2Length = s2.Length; 

Ini akan berhasil dikompilasi. Namun, ketika kita menjalankan ini, kita akan mendapatkan NullReferenceException, untuk itu kita akan dipaksa keluar untuk melindungi semua kode dari kemungkinan adanya null. Ini membosankan cukup cepat, bahkan jika Anda memiliki kelas perlindungan kecil yang menyenangkan yang akan memeriksa nilainya dan menanganinya / melempar pengecualian yang lebih bermakna.

Cuplikan layar ini menggunakan LinqPad, jadi mungkin tampak sedikit tidak biasa jika Anda belum pernah melihat LinqPad sebelumnya, tapi percayalah, Anda masih mendapatkan hasil yang sama dalam IDE yang berbeda.

gambar

Sekarang mari kita lihat bagaimana kode ekuivalen dalam F # akan terlihat

 let s1 = "Cats" let s1Length = s1.Length; let s2 = None let s2Length = s2.Length; //excplicily string typed None let s3 = Option.None let s3Length = s3.Length; 

Pada kode ini, Anda akan mendapatkan kesalahan kompilasi langsung, karena s3 akan dianggap tipe lain yang tidak memiliki properti "Panjang".

Perbandingan Opsi


Jenis opsi dianggap sama, mereka dari jenis yang sama, dan bahwa jenis yang dikandungnya sama, yang mematuhi aturan kesetaraan dari jenis yang dimiliki.

Jadi hal semacam ini dapat menyebabkan kesalahan waktu kompilasi langsung di F #

 let o1 = Some 1 let o2 = Some "Cats" printfn "o1=o2 : %b" (o1 = o2) 

gambar

Ini akan berfungsi seperti yang diharapkan karena tipenya sama

 let o1 = Some "Cats" let o2 = Some "Cats" let o3 = Some "cats" printfn "o1=o2 : %b" (o1 = o2) printfn "o2=o3 : %b" (o2 = o3) 

gambar

Source: https://habr.com/ru/post/id470918/


All Articles