Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Topik ini menjelaskan cara membebani operator aritmetika dalam kelas atau jenis catatan, dan di tingkat global.
Sintaksis
// Overloading an operator as a class or record member.
static member (operator-symbols) (parameter-list) =
method-body
// Overloading an operator at the global level
let [inline] (operator-symbols) parameter-list = function-body
Komentar
Dalam sintaks sebelumnya, simbol operator adalah salah satu dari +, , -, */, =, dan sebagainya. Daftar parameter menentukan operand dalam urutan muncul dalam sintaks yang biasa untuk operator tersebut.
Metode-isi membangun nilai yang dihasilkan.
Operator kelebihan beban untuk operator harus statis. Operator kelebihan beban untuk operator unary, seperti + dan -, harus menggunakan tilde (~) dalam simbol operator untuk menunjukkan bahwa operator adalah operator unary dan bukan operator biner, seperti yang ditunjukkan dalam deklarasi berikut.
static member (~-) (v : Vector)
Kode berikut mengilustrasikan kelas vektor yang hanya memiliki dua operator, satu untuk minus tidak biasa dan satu untuk perkalian dengan skalar. Dalam contoh, dua kelebihan beban untuk perkalian skalar diperlukan karena operator harus bekerja terlepas dari urutan munculnya vektor dan skalar.
type Vector(x: float, y : float) =
member this.x = x
member this.y = y
static member (~-) (v : Vector) =
Vector(-1.0 * v.x, -1.0 * v.y)
static member (*) (v : Vector, a) =
Vector(a * v.x, a * v.y)
static member (*) (a, v: Vector) =
Vector(a * v.x, a * v.y)
override this.ToString() =
this.x.ToString() + " " + this.y.ToString()
let v1 = Vector(1.0, 2.0)
let v2 = v1 * 2.0
let v3 = 2.0 * v1
let v4 = - v2
printfn "%s" (v1.ToString())
printfn "%s" (v2.ToString())
printfn "%s" (v3.ToString())
printfn "%s" (v4.ToString())
Hasil:
1 2
2 4
2 4
-2 -4
Membuat Operator Baru
Anda dapat membebani semua operator standar, tetapi Anda juga dapat membuat operator baru dari urutan karakter tertentu. Karakter operator yang diizinkan adalah !, , $%, &, *, +, -, ./, <, =, >, ?, @, ^, , |, dan ~. Karakter ~ ini memiliki arti khusus untuk membuat operator unary, dan bukan bagian dari urutan karakter operator. Tidak semua operator dapat dibuat unary.
Tergantung pada urutan karakter yang tepat yang Anda gunakan, operator Anda akan memiliki prioritas dan associativity tertentu. Asokiativitas dapat berupa kiri ke kanan atau kanan ke kiri dan digunakan setiap kali operator dengan tingkat prioritas yang sama muncul secara berurutan tanpa tanda kurung.
Karakter . operator tidak memengaruhi prioritas, sehingga, misalnya, jika Anda ingin menentukan versi perkalian Anda sendiri yang memiliki prioritas dan asokiativitas yang sama dengan perkalian biasa, Anda dapat membuat operator seperti .*.
Operator $ harus berdiri sendiri dan tanpa simbol tambahan.
Tabel yang memperlihatkan prioritas semua operator di F# dapat ditemukan di Simbol dan Referensi Operator.
Nama Operator Kelebihan Beban
Ketika pengkompilasi F# mengkompilasi ekspresi operator, ia menghasilkan metode yang memiliki nama yang dihasilkan kompilator untuk operator tersebut. Ini adalah nama yang muncul dalam bahasa perantara umum (CIL) untuk metode , dan juga dalam refleksi dan IntelliSense. Anda biasanya tidak perlu menggunakan nama-nama ini dalam kode F#.
Tabel berikut menunjukkan operator standar dan nama yang dihasilkan terkait.
| Pengoperasi | Nama yang dihasilkan |
|---|---|
[] |
op_Nil |
:: |
op_Cons |
+ |
op_Addition |
- |
op_Subtraction |
* |
op_Multiply |
/ |
op_Division |
@ |
op_Append |
^ |
op_Concatenate |
% |
op_Modulus |
&&& |
op_BitwiseAnd |
||| |
op_BitwiseOr |
^^^ |
op_ExclusiveOr |
<<< |
op_LeftShift |
~~~ |
op_LogicalNot |
>>> |
op_RightShift |
~+ |
op_UnaryPlus |
~- |
op_UnaryNegation |
= |
op_Equality |
<= |
op_LessThanOrEqual |
>= |
op_GreaterThanOrEqual |
< |
op_LessThan |
> |
op_GreaterThan |
? |
op_Dynamic |
?<- |
op_DynamicAssignment |
|> |
op_PipeRight |
<| |
op_PipeLeft |
! |
op_Dereference |
>> |
op_ComposeRight |
<< |
op_ComposeLeft |
<@ @> |
op_Quotation |
<@@ @@> |
op_QuotationUntyped |
+= |
op_AdditionAssignment |
-= |
op_SubtractionAssignment |
*= |
op_MultiplyAssignment |
/= |
op_DivisionAssignment |
.. |
op_Range |
.. .. |
op_RangeStep |
Perhatikan bahwa not operator di F# tidak memancarkan op_Inequality karena bukan operator simbolis. Ini adalah fungsi yang memancarkan IL yang meniadakan ekspresi boolean.
Kombinasi karakter operator lain yang tidak tercantum di sini dapat digunakan sebagai operator dan memiliki nama yang dibuat dengan menggabungkan nama untuk karakter individual dari tabel berikut. Misalnya, +! menjadi op_PlusBang.
| Karakter operator | Nama |
|---|---|
> |
Greater |
< |
Less |
+ |
Plus |
- |
Minus |
* |
Multiply |
/ |
Divide |
= |
Equals |
~ |
Twiddle |
$ |
Dollar |
% |
Percent |
. |
Dot |
& |
Amp |
| |
Bar |
@ |
At |
^ |
Hat |
! |
Bang |
? |
Qmark |
( |
LParen |
, |
Comma |
) |
RParen |
[ |
LBrack |
] |
RBrack |
: |
Colon |
Penggunaan : dalam operator kustom dicadangkan sebagian. Ini hanya dapat digunakan dalam operator di mana karakter pertama adalah > atau . di mana karakter pertama setelah sejumlah di depan . adalah > misalnya >: atau .>:.
Operator Awalan dan Infiks
Operator awalan diharapkan ditempatkan di depan operand atau operand, seperti fungsi. Operator infiks diharapkan ditempatkan di antara dua operan.
Hanya operator tertentu yang dapat digunakan sebagai operator awalan. Beberapa operator selalu merupakan operator awalan, yang lain dapat berupa infiks atau awalan, dan sisanya selalu merupakan operator infiks. Operator yang dimulai dengan !, kecuali !=, dan operator ~, atau urutan berulang dari ~, selalu merupakan operator awalan. Operator +, , -, +.-., &, &&, %, dan %% dapat menjadi operator awalan atau operator infiks. Anda membedakan versi awalan operator ini dari versi infiks dengan menambahkan ~ di awal operator awalan saat ditentukan.
~ tidak digunakan saat Anda menggunakan operator, hanya ketika ditentukan.
Contoh
Kode berikut mengilustrasikan penggunaan kelebihan beban operator untuk mengimplementasikan jenis pecahan. Pecahan diwakili oleh pembilang dan denominator. Fungsi hcf ini digunakan untuk menentukan faktor umum tertinggi, yang digunakan untuk mengurangi pecahan.
// Determine the highest common factor between
// two positive integers, a helper for reducing
// fractions.
let rec hcf a b =
if a = 0u then b
elif a<b then hcf a (b - a)
else hcf (a - b) b
// type Fraction: represents a positive fraction
// (positive rational number).
type Fraction =
{
// n: Numerator of fraction.
n : uint32
// d: Denominator of fraction.
d : uint32
}
// Produce a string representation. If the
// denominator is "1", do not display it.
override this.ToString() =
if (this.d = 1u)
then this.n.ToString()
else this.n.ToString() + "/" + this.d.ToString()
// Add two fractions.
static member (+) (f1 : Fraction, f2 : Fraction) =
let nTemp = f1.n * f2.d + f2.n * f1.d
let dTemp = f1.d * f2.d
let hcfTemp = hcf nTemp dTemp
{ n = nTemp / hcfTemp; d = dTemp / hcfTemp }
// Adds a fraction and a positive integer.
static member (+) (f1: Fraction, i : uint32) =
let nTemp = f1.n + i * f1.d
let dTemp = f1.d
let hcfTemp = hcf nTemp dTemp
{ n = nTemp / hcfTemp; d = dTemp / hcfTemp }
// Adds a positive integer and a fraction.
static member (+) (i : uint32, f2: Fraction) =
let nTemp = f2.n + i * f2.d
let dTemp = f2.d
let hcfTemp = hcf nTemp dTemp
{ n = nTemp / hcfTemp; d = dTemp / hcfTemp }
// Subtract one fraction from another.
static member (-) (f1 : Fraction, f2 : Fraction) =
if (f2.n * f1.d > f1.n * f2.d)
then failwith "This operation results in a negative number, which is not supported."
let nTemp = f1.n * f2.d - f2.n * f1.d
let dTemp = f1.d * f2.d
let hcfTemp = hcf nTemp dTemp
{ n = nTemp / hcfTemp; d = dTemp / hcfTemp }
// Multiply two fractions.
static member (*) (f1 : Fraction, f2 : Fraction) =
let nTemp = f1.n * f2.n
let dTemp = f1.d * f2.d
let hcfTemp = hcf nTemp dTemp
{ n = nTemp / hcfTemp; d = dTemp / hcfTemp }
// Divide two fractions.
static member (/) (f1 : Fraction, f2 : Fraction) =
let nTemp = f1.n * f2.d
let dTemp = f2.n * f1.d
let hcfTemp = hcf nTemp dTemp
{ n = nTemp / hcfTemp; d = dTemp / hcfTemp }
// A full set of operators can be quite lengthy. For example,
// consider operators that support other integral data types,
// with fractions, on the left side and the right side for each.
// Also consider implementing unary operators.
let fraction1 = { n = 3u; d = 4u }
let fraction2 = { n = 1u; d = 2u }
let result1 = fraction1 + fraction2
let result2 = fraction1 - fraction2
let result3 = fraction1 * fraction2
let result4 = fraction1 / fraction2
let result5 = fraction1 + 1u
printfn "%s + %s = %s" (fraction1.ToString()) (fraction2.ToString()) (result1.ToString())
printfn "%s - %s = %s" (fraction1.ToString()) (fraction2.ToString()) (result2.ToString())
printfn "%s * %s = %s" (fraction1.ToString()) (fraction2.ToString()) (result3.ToString())
printfn "%s / %s = %s" (fraction1.ToString()) (fraction2.ToString()) (result4.ToString())
printfn "%s + 1 = %s" (fraction1.ToString()) (result5.ToString())
Hasil:
3/4 + 1/2 = 5/4
3/4 - 1/2 = 1/4
3/4 * 1/2 = 3/8
3/4 / 1/2 = 3/2
3/4 + 1 = 7/4
Operator di Tingkat Global
Anda juga dapat menentukan operator di tingkat global. Kode berikut mendefinisikan operator +?.
let inline (+?) (x: int) (y: int) = x + 2*y
printf "%d" (10 +? 1)
Output dari kode di atas adalah 12.
Anda dapat menentukan ulang operator aritmatika reguler dengan cara ini karena aturan cakupan untuk F# menentukan bahwa operator yang baru ditentukan lebih diutamakan daripada operator bawaan.
Kata kunci inline sering digunakan dengan operator global, yang seringkali merupakan fungsi kecil yang paling baik diintegrasikan ke dalam kode panggilan. Membuat fungsi operator sebaris juga memungkinkan mereka untuk bekerja dengan parameter jenis yang diselesaikan secara statis untuk menghasilkan kode generik yang diselesaikan secara statis. Untuk informasi selengkapnya, lihat Fungsi Sebaris dan Parameter Jenis yang Diselesaikan Secara Statis.