İşleç Aşırı Yüklemesi
Bu konuda, bir sınıf veya kayıt türünde ve genel düzeyde aritmetik işleçleri aşırı yükleme açıklanmıştır.
Syntax
// 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
Açıklamalar
Önceki söz dizimsinde işleç-sembolü + , , , , , ve gibi - * / = ifadelerden birisidir. parametre-listesi, işlenenleri bu işleç için normal söz dizimsinde görünme sırasına göre belirtir. method-body, sonuçta elde edilen değeri verir.
İşleçler için işleç aşırı yüklemeleri statik olmalıdır. ve gibi birli işleçler için işleç aşırı yüklemeleri, işlecin aşağıdaki bildirimde gösterildiği gibi ikili işleç değil birli işleç olduğunu belirtmek için işleç sembolünde + - bir tilde ( ~ ) kullandır.
static member (~-) (v : Vector)
Aşağıdaki kod, yalnızca iki işleci olan bir vektör sınıfını göstermektedir: birli eksi için ve bir skaler tarafından çarpma için bir. Örnekte, skaler çarpma için iki aşırı yükleme gerekir, çünkü işleç vektör ve skaler'ın hangi sırada görünse de çalışması gerekir.
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())
Yeni İşleçler Oluşturma
Tüm standart işleçleri aşırı yükleyebilirsiniz, ancak belirli karakter dizileri dışında yeni işleçler de oluşturabilirsiniz. İzin verilen işleç karakterleri ! , , , , , , $ , , % , , , & , * , + - ve . / < = > ? @ ^ | ~ karakterleridir. karakteri, ~ bir işleci birli yapmak için özel bir anlamı vardır ve işleç karakter dizisinin bir parçası değildir. Tüm işleçler birli olarak gerçekleştirilene değildir.
Kullandığınız tam karakter dizisine bağlı olarak, işleciniz belirli bir önceliğe ve birlikteliğe sahip olur. Birliktelik soldan sağa veya sağdan sola olabilir ve aynı öncelik düzeyine sahip işleçler parantez olmadan sırayla her görüntüde kullanılır.
İşleç karakteri önceliği etkilemez; bu nedenle, örneğin, normal çarpmayla aynı önceliğe ve birlikteliğe sahip kendi çarpma sürümünüz tanımlamak için . gibi işleçler .* oluşturabilirsiniz.
Yalnızca ve ? ?<- işleçleri ile ? başlayabilir.
$İşleç tek başına ve ek semboller olmadan dursun.
F# içinde tüm işleçlerin öncellik gösteren bir tablo Sembol ve İşleç Başvurusu içinde bulunabilir.
Aşırı Yüklenmiş İşleç Adları
F# derleyicisi bir işleç ifadesini derleyene, bu işleç için derleyici tarafından oluşturulan bir adı olan bir yöntem üretir. Bu, yöntemi için Microsoft ara dilinde (MSIL) ve yansıma ile IntelliSense'te görünen addır. Normalde bu adları F# kodunda kullanmak zorunda değildir.
Aşağıdaki tablo standart işleçleri ve karşılık gelen oluşturulan adlarını gösterir.
| Operatör | Oluşturulan ad |
|---|---|
[] |
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 |
notF# işlecinin sembolik bir işleç op_Inequality olmadığını unutmayın. Bir boole ifadesini olumsuz alan IL yayı bir işlevdir.
Burada listelenmiyor olan işleç karakterlerinin diğer birleşimleri işleç olarak kullanılabilir ve adları aşağıdaki tabloda yer alan tek tek karakterlerin adları bir arada tutularak kullanılmaktadır. Örneğin, +! op_PlusBangolur.
| İşleç karakteri | Name |
|---|---|
> |
Greater |
< |
Less |
+ |
Plus |
- |
Minus |
* |
Multiply |
/ |
Divide |
= |
Equals |
~ |
Twiddle |
$ |
Dollar |
% |
Percent |
. |
Dot |
& |
Amp |
| |
Bar |
@ |
At |
^ |
Hat |
! |
Bang |
? |
Qmark |
( |
LParen |
, |
Comma |
) |
RParen |
[ |
LBrack |
] |
RBrack |
Önek ve Düzeltme İşleçleri
Ön ek işleçlerinin, bir işleve çok benzer şekilde bir işlenenin veya işlenenlerin önüne yerleştirilleri beklenir. Sonek işleçlerin iki işlenen arasına yerleştirilmeleri beklenir.
Yalnızca belirli işleçler ön ek işleçleri olarak kullanılabilir. Bazı işleçler her zaman önek işleçleridir, diğerleri sabit veya ön ek olabilir ve geri kalanı her zaman sabit işleçleridir. ile başlayan ! işleçler, != dışında ve işleci ~ veya yinelenen dizileri her zaman ~ önek işleçleridir. , + , - , , , , +. , ve -. & && % %% işleçleri, önek işleçleri veya sonek işleçleri olabilir. Tanımlandığı zaman ön ek işlecinin başına bir ekleyerek bu işleçlerin ön ek sürümünü son ek ~ sürümünden ayırt edebilirsiniz. ~işleci kullanılırken, yalnızca tanımlandığı zaman kullanılmaz.
Örnek
Aşağıdaki kod, bir kesir türü uygulamak için işleç aşırı yükleme kullanımını göstermektedir. Kesir bir payda ve payda ile temsil edildi. işlevi, hcf kesirleri azaltmak için kullanılan en yüksek ortak faktörü belirlemek için kullanılır.
// 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())
Çıkış:
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
Genel Düzeyde İşleçler
İşleçleri genel düzeyde de tanımlayabilirsiniz. Aşağıdaki kod bir işleci +? tanımlar.
let inline (+?) (x: int) (y: int) = x + 2*y
printf "%d" (10 +? 1)
Yukarıdaki kodun çıktısı: 12 .
F# için kapsam kuralları yeni tanımlanan işleçlerin yerleşik işleçlere göre öncelikli olduğunu dikte ettiği için, normal aritmetik işleçleri bu şekilde yeniden tanım edebilirsiniz.
anahtar sözcüğü genellikle çağrı koduyla en iyi şekilde tümleştirilmiş küçük işlevler inline olan genel işleçlerle kullanılır. İşleç işlevlerini satır içi yapmak, statik olarak çözümlenmiş genel kod üretmek için statik olarak çözümlenmiş tür parametreleriyle çalışmalarına da olanak sağlar. Daha fazla bilgi için bkz. Satır Içi İşlevler ve Statik Olarak Çözümlenmiş Tür Parametreleri.