Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Toto téma popisuje, jak přetěžovat aritmetické operátory v typu třídy nebo záznamu a na globální úrovni.
Syntaxe
// 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
Poznámky
V předchozí syntaxi je symbol operátoru jedním z +, -, *, /, , =atd. Seznam parametrů určuje operandy v pořadí, v jakém se zobrazují v obvyklé syntaxi daného operátoru. Tělo metody vytvoří výslednou hodnotu.
Přetížení operátorů pro operátory musí být statické. Přetížení operátoru pro unární operátory, například + a -, musí v ~ použít vlnovku () k označení, že operátor je unární operátor a nikoli binární operátor, jak je znázorněno v následující deklaraci.
static member (~-) (v : Vector)
Následující kód znázorňuje vektorovou třídu, která má pouze dva operátory, jeden pro unární minus a jeden pro násobení skalárem. V tomto příkladu jsou potřeba dvě přetížení skalárního násobení, protože operátor musí fungovat bez ohledu na pořadí, ve kterém se vektor a skalární zobrazí.
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())
Výstup:
1 2
2 4
2 4
-2 -4
Vytváření nových operátorů
Můžete přetížit všechny standardní operátory, ale můžete také vytvořit nové operátory z posloupností určitých znaků. Povolené znaky operátoru jsou , , , !$%&*+-./<=>, ?, a .@^|~ Znak ~ má zvláštní význam vytvoření operátoru unární a není součástí sekvence znaků operátoru. Ne všechny operátory mohou být unární.
V závislosti na přesné sekvenci znaků, kterou použijete, bude mít operátor určitou prioritu a asociativitu. Asociativita může být zleva doprava nebo zprava doleva a používá se vždy, když se operátory stejné úrovně priority zobrazí v posloupnosti bez závorek.
Znak . operátoru nemá vliv na prioritu, takže například pokud chcete definovat vlastní verzi násobení, která má stejnou prioritu a asociativitu jako běžné násobení, můžete vytvořit operátory, jako .*je .
Operátor $ musí být samostatný a bez dalších symbolů.
Tabulku, která zobrazuje prioritu všech operátorů v jazyce F#, najdete v odkazu na symboly a operátory.
Přetížené názvy operátorů
Když kompilátor jazyka F# zkompiluje výraz operátoru, vygeneruje metodu, která má pro tento operátor vygenerovaný název kompilátoru. Toto je název, který se zobrazí v běžném zprostředkujícím jazyce (CIL) pro metodu, a také v reflexi a IntelliSense. V kódu jazyka F# obvykle tyto názvy nemusíte používat.
Následující tabulka uvádí standardní operátory a jejich odpovídající vygenerované názvy.
| Operátor | Vygenerovaný název |
|---|---|
[] |
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 |
Všimněte si, že not operátor v jazyce F# negeneruje op_Inequality , protože se nejedná o symbolický operátor. Jedná se o funkci, která generuje il, která neguje logický výraz.
Další kombinace znaků operátorů, které zde nejsou uvedeny, lze použít jako operátory a mají názvy, které jsou tvořeny zřetězením názvů jednotlivých znaků z následující tabulky. Například +! se stane op_PlusBang.
| Znak operátoru | Název |
|---|---|
> |
Greater |
< |
Less |
+ |
Plus |
- |
Minus |
* |
Multiply |
/ |
Divide |
= |
Equals |
~ |
Twiddle |
$ |
Dollar |
% |
Percent |
. |
Dot |
& |
Amp |
| |
Bar |
@ |
At |
^ |
Hat |
! |
Bang |
? |
Qmark |
( |
LParen |
, |
Comma |
) |
RParen |
[ |
LBrack |
] |
RBrack |
: |
Colon |
: Použití ve vlastních operátorech je částečně vyhrazeno. Lze jej použít pouze v operátorech, jejichž prvním znakem je > nebo kde je první znak po libovolném počtu počátečních .> znaků např. >: nebo .>:. .
Operátory předpony a přípony
Před operandy nebo operandy se očekávají operátory předponami, podobně jako u funkce. Očekává se, že operátory infixu budou umístěny mezi dvěma operandy.
Jako operátory předpon lze použít pouze určité operátory. Některé operátory jsou vždy operátory předpon, jiné můžou být infixní nebo předponou a ostatní operátory jsou vždy infixní. Operátory, které začínají operátorem !, s výjimkou !=a operátorem ~, nebo opakovanými ~sekvencemi , jsou vždy operátory předpon. Operátory +, , -, +., -.&, , &&%, a %% mohou být operátory předpony nebo infix operátory. Verzi předpony těchto operátorů od verze infixu odlišíte přidáním ~ operátoru předpony na začátek operátoru předpony, když je definován. Nepoužívá se ~ při použití operátoru, pouze pokud je definován.
Příklad
Následující kód znázorňuje použití přetížení operátoru k implementaci typu zlomku. Zlomek je reprezentován čitatelem a jmenovatelem. Funkce hcf se používá k určení nejvyššího společného faktoru, který se používá ke snížení zlomků.
// 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())
Výstup:
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
Operátory na globální úrovni
Operátory můžete definovat také na globální úrovni. Následující kód definuje operátor +?.
let inline (+?) (x: int) (y: int) = x + 2*y
printf "%d" (10 +? 1)
Výstupem výše uvedeného kódu je 12.
Tímto způsobem můžete předefinovat běžné aritmetické operátory, protože pravidla oborů pro jazyk F# určují, že nově definované operátory mají přednost před předdefinované operátory.
Klíčové slovo inline se často používá s globálními operátory, což jsou často malé funkce, které jsou nejlépe integrovány do volajícího kódu. Funkce operátoru vložené také umožňují pracovat se staticky vyřešenými parametry typu a vytvářet staticky vyřešený obecný kód. Další informace najdete v tématu Vložené funkce a staticky vyřešené parametry typu.