Bagikan melalui


Transmisi dan konversi (F#)

Artikel ini menjelaskan dukungan untuk konversi jenis di F#.

Jenis Aritmatika

F# menyediakan operator konversi untuk konversi aritmatika antara berbagai jenis primitif, seperti antara jenis bilangan bulat dan titik pecahan. Operator konversi integral dan karakter telah memeriksa dan menghapus centang formulir; operator titik mengambang dan enum operator konversi tidak. Formulir yang tidak dicentang didefinisikan di FSharp.Core.Operators dan formulir yang dicentang ditentukan dalam FSharp.Core.Operators.Checked. Formulir yang dicentang memeriksa luapan dan menghasilkan pengecualian runtime jika nilai yang dihasilkan melebihi batas jenis target.

Masing-masing operator ini memiliki nama yang sama dengan nama jenis tujuan. Misalnya, dalam kode berikut, di mana jenis secara eksplisit dianotasikan, byte muncul dengan dua arti yang berbeda. Kemunculan pertama adalah jenis dan yang kedua adalah operator konversi.

let x : int = 5

let b : byte = byte x

Tabel berikut menunjukkan operator konversi yang ditentukan dalam F#.

Pengoperasi Deskripsi
byte Konversi ke byte, jenis tidak ditandatangani 8-bit.
sbyte Konversi ke byte yang ditandatangani.
int16 Konversi ke bilangan bulat bertanda tangan 16-bit.
uint16 Konversi ke bilangan bulat yang tidak ditandatangani 16-bit.
int32, int Konversi ke bilangan bulat bertanda tangan 32-bit.
uint32 Konversi ke bilangan bulat yang tidak ditandatangani 32-bit.
int64 Konversi ke bilangan bulat bertanda tangan 64-bit.
uint64 Konversi ke bilangan bulat yang tidak ditandatangani 64-bit.
nativeint Konversi ke bilangan bulat asli.
unativeint Konversi ke bilangan bulat asli yang tidak ditandatangani.
float, double Konversikan ke angka titik mengambang IEEE presisi ganda 64-bit.
float32, single Konversi ke angka titik mengambang IEEE presisi tunggal 32-bit.
decimal Konversi ke System.Decimal.
char Konversi ke System.Char, karakter Unicode.
enum Konversi ke jenis enumerasi.

Selain jenis primitif bawaan, Anda dapat menggunakan operator ini dengan jenis yang mengimplementasikan op_Explicit atau op_Implicit metode dengan tanda tangan yang sesuai. Misalnya, int operator konversi bekerja dengan jenis apa pun yang menyediakan metode op_Explicit statis yang mengambil jenis sebagai parameter dan mengembalikan int. Sebagai pengecualian khusus untuk aturan umum bahwa metode tidak dapat kelebihan beban berdasarkan jenis pengembalian, Anda dapat melakukan ini untuk op_Explicit dan op_Implicit.

Jenis Enumerasi

Operator enum adalah operator generik yang mengambil satu parameter jenis yang mewakili jenis yang akan dikonversi enum . Saat dikonversi ke jenis enumerasi, ketik inferensi mencoba menentukan jenis enum yang ingin Anda konversi. Dalam contoh berikut, variabel col1 tidak secara eksplisit dianotasikan, tetapi jenisnya disimpulkan dari pengujian kesetaraan yang lebih baru. Oleh karena itu, kompilator dapat menyimpulkan bahwa Anda mengonversi ke Color enumerasi. Atau, Anda dapat menyediakan anotasi jenis, seperti col2 dalam contoh berikut.

type Color =
    | Red = 1
    | Green = 2
    | Blue = 3

// The target type of the conversion cannot be determined by type inference, so the type parameter must be explicit.
let col1 = enum<Color> 1

// The target type is supplied by a type annotation.
let col2 : Color = enum 2

Anda juga dapat menentukan jenis enumerasi target secara eksplisit sebagai parameter jenis, seperti dalam kode berikut:

let col3 = enum<Color> 3

Perhatikan bahwa enumerasi yang ditransmisikan hanya berfungsi jika jenis enumerasi yang mendasar kompatibel dengan jenis yang sedang dikonversi. Dalam kode berikut, konversi gagal dikompilasi karena ketidakcocokan antara int32 dan uint32.

// Error: types are incompatible
let col4 : Color = enum 2u

Untuk informasi selengkapnya, lihat Enumerasi.

Jenis Objek Casting

Konversi antara jenis dalam hierarki objek sangat mendasar untuk pemrograman berorientasi objek. Ada dua jenis konversi dasar: casting up (upcasting) dan casting down (downcasting). Mentransmisikan hierarki berarti transmisi dari referensi objek turunan ke referensi objek dasar. Pemeran semacam itu dijamin berfungsi selama kelas dasar berada dalam hierarki warisan kelas turunan. Mentransmisikan hierarki, dari referensi objek dasar ke referensi objek turunan, hanya berhasil jika objek sebenarnya adalah instans jenis tujuan (turunan) yang benar atau jenis yang berasal dari jenis tujuan.

F# menyediakan operator untuk jenis konversi ini. Operator :> mentransmisikan hierarki, dan :?> operator mentransmisikan hierarki.

Upcasting

Dalam banyak bahasa berorientasi objek, upcasting bersifat implisit; di F#, aturannya sedikit berbeda. Upcasting diterapkan secara otomatis saat Anda meneruskan argumen ke metode pada jenis objek. Namun, untuk fungsi let-bound dalam modul, upcasting tidak otomatis, kecuali jenis parameter dinyatakan sebagai jenis fleksibel. Untuk informasi selengkapnya, lihat Jenis Fleksibel.

Operator :> melakukan pemeran statis, yang berarti bahwa keberhasilan pemeran ditentukan pada waktu kompilasi. Jika cast yang berhasil menggunakan :> kompilasi, itu adalah cast yang valid dan tidak memiliki kemungkinan kegagalan pada run time.

Anda juga dapat menggunakan upcast operator untuk melakukan konversi tersebut. Ekspresi berikut menentukan konversi hierarki:

upcast expression

Saat Anda menggunakan operator upcast, pengkompilasi mencoba menyimpulkan jenis yang Anda konversi dari konteks. Jika pengkompilasi tidak dapat menentukan jenis target, pengkompilasi melaporkan kesalahan. Anotasi jenis mungkin diperlukan.

Konversi Tipe Ke Turunan (Downcasting)

Operator :?> melakukan pemeran dinamis, yang berarti bahwa keberhasilan pemeran ditentukan pada waktu proses. Transmisi yang menggunakan :?> operator tidak diperiksa pada waktu kompilasi; tetapi pada waktu proses, upaya dilakukan untuk mentransmisikan ke jenis yang ditentukan. Jika objek kompatibel dengan jenis target, pemeran berhasil. Jika objek tidak kompatibel dengan jenis target, runtime akan menaikkan InvalidCastException.

Anda juga dapat menggunakan downcast operator untuk melakukan konversi jenis dinamis. Ekspresi berikut menentukan konversi hierarki ke jenis yang disimpulkan dari konteks program:

downcast expression

Adapun upcast operator, jika pengkompilasi tidak dapat menyimpulkan jenis target tertentu dari konteks, ia melaporkan kesalahan. Anotasi jenis mungkin diperlukan.

Kode berikut mengilustrasikan penggunaan :> operator dan :?> . Kode ini menggambarkan bahwa :?> operator paling baik digunakan ketika Anda tahu bahwa konversi akan berhasil, karena melemparkan InvalidCastException jika konversi gagal. Jika Anda tidak tahu bahwa konversi akan berhasil, pengujian jenis yang menggunakan match ekspresi lebih baik karena menghindari overhead menghasilkan pengecualian.

type Base1() =
    abstract member F : unit -> unit
    default u.F() =
     printfn "F Base1"

type Derived1() =
    inherit Base1()
    override u.F() =
      printfn "F Derived1"


let d1 : Derived1 = Derived1()

// Upcast to Base1.
let base1 = d1 :> Base1

// This might throw an exception, unless
// you are sure that base1 is really a Derived1 object, as
// is the case here.
let derived1 = base1 :?> Derived1

// If you cannot be sure that b1 is a Derived1 object,
// use a type test, as follows:
let downcastBase1 (b1 : Base1) =
   match b1 with
   | :? Derived1 as derived1 -> derived1.F()
   | _ -> ()

downcastBase1 base1

Karena operator downcast generik dan upcast mengandalkan inferensi jenis untuk menentukan argumen dan jenis pengembalian, Anda dapat mengganti let base1 = d1 :> Base1 dalam contoh kode sebelumnya dengan let base1: Base1 = upcast d1.

Anotasi jenis diperlukan, karena upcast dengan sendirinya tidak dapat menentukan kelas dasar.

Konversi upcast implisit

Upcast implisit disisipkan dalam situasi berikut:

  • Saat memberikan parameter ke fungsi atau metode dengan jenis bernama yang diketahui. Ini termasuk ketika konstruksi seperti ekspresi komputasi atau pemotongan menjadi panggilan metode.

  • Saat menetapkan ke atau bermutasi bidang rekaman atau properti yang memiliki jenis bernama yang diketahui.

  • Ketika cabang ekspresi if/then/else atau match memiliki jenis target yang diketahui yang timbul dari cabang lain atau jenis yang diketahui secara keseluruhan.

  • Saat elemen ekspresi daftar, array, atau urutan memiliki jenis target yang diketahui.

Misalnya, pertimbangkan kode berikut:

open System
open System.IO

let findInputSource () : TextReader =
    if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
        // On Monday a TextReader
        Console.In
    else
        // On other days a StreamReader
        File.OpenText("path.txt")

Di sini cabang komputasi bersyarat dan TextReaderStreamReader masing-masing. Pada cabang kedua, jenis target yang diketahui berasal TextReader dari anotasi jenis pada metode , dan dari cabang pertama. Ini berarti tidak ada upcast yang diperlukan pada cabang kedua.

Untuk menampilkan peringatan di setiap titik, upcast implisit tambahan digunakan, Anda dapat mengaktifkan peringatan 3388 (/warnon:3388 atau properti <WarnOn>3388</WarnOn>).

Konversi numerik implisit

F# menggunakan pelesiran eksplisit jenis numerik dalam banyak kasus melalui operator konversi. Misalnya, pelesiran eksplisit diperlukan untuk sebagian besar jenis numerik, seperti int8 atau int16, atau dari float32 ke float64, atau ketika jenis sumber atau tujuan tidak diketahui.

Namun, pellebaran implisit diizinkan untuk bilangan bulat 32-bit yang diperlebar menjadi bilangan bulat 64-bit, dalam situasi yang sama dengan upcast implisit. Misalnya, pertimbangkan bentuk API umum:

type Tensor(…) =
    static member Create(sizes: seq<int64>) = Tensor(…)

Literal bilangan bulat untuk int64 dapat digunakan:

Tensor.Create([100L; 10L; 10L])

Atau literal bilangan bulat untuk int32:

Tensor.Create([int64 100; int64 10; int64 10])

Pelesiran terjadi secara otomatis untuk int32 , int32 ke int64nativeint, dan int32 ke double, ketika jenis sumber dan tujuan diketahui selama inferensi jenis. Jadi dalam kasus seperti contoh sebelumnya, int32 literal dapat digunakan:

Tensor.Create([100; 10; 10])

Anda juga dapat secara opsional mengaktifkan peringatan 3389 (/warnon:3389 atau properti <WarnOn>3389</WarnOn>) untuk menunjukkan peringatan di setiap titik pelesiran numerik implisit digunakan.

. Konversi implisit gaya NET

API .NET memungkinkan definisi op_Implicit metode statis untuk menyediakan konversi implisit antar jenis. Ini diterapkan secara otomatis dalam kode F# saat meneruskan argumen ke metode. Misalnya, pertimbangkan kode berikut yang melakukan panggilan eksplisit ke op_Implicit metode:

open System.Xml.Linq

let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants(XName.op_Implicit "Item")

. Konversi gaya op_Implicit NET diterapkan secara otomatis untuk ekspresi argumen saat jenis tersedia untuk ekspresi sumber dan jenis target:

open System.Xml.Linq

let purchaseOrder = XElement.Load("PurchaseOrder.xml")
let partNos = purchaseOrder.Descendants("Item")

Anda juga dapat secara opsional mengaktifkan peringatan 3395 (/warnon:3395 atau properti <WarnOn>3395</WarnOn>) untuk menunjukkan peringatan di setiap titik a . Konversi implisit gaya NET digunakan.

. Konversi gaya op_Implicit NET juga diterapkan secara otomatis untuk ekspresi argumen non-metode dalam situasi yang sama dengan upcast implisit. Namun, ketika digunakan secara luas atau tidak pantas, konversi implisit dapat berinteraksi dengan buruk dengan inferensi jenis dan menyebabkan kode yang lebih sulit dipahami. Untuk alasan ini, ini selalu menghasilkan peringatan ketika digunakan dalam posisi non-argumen.

Untuk menunjukkan peringatan di setiap titik bahwa . Konversi implisit gaya NET digunakan untuk argumen non-metode, Anda dapat mengaktifkan peringatan 3391 (/warnon:3391 atau properti <WarnOn>3391</WarnOn>).

Peringatan opsional berikut disediakan untuk penggunaan konversi implisit:

  • /warnon:3388 (peningkatan implisit tambahan)
  • /warnon:3389 (pelesiran numerik implisit)
  • /warnon:3391 (op_Implicit pada argumen non-metode, aktif secara default)
  • /warnon:3395 (op_Implicit pada argumen metode)

Lihat juga