Přetížení operátoru (F#)
Toto téma popisuje, jak přetěžovat aritmetické operátory do třídy nebo typu záznamu a na globální úrovni.
// 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
In the previous syntax, the operator-symbol is one of +, -, *, /, =, and so on.parameter-list v pořadí jsou zobrazeny v obvyklých syntaxi pro tento operátor určuje operandy.method-body Vytvoří výslednou hodnotu.
Přetížení operátor pro hospodářské subjekty musí být statická.Operátor přetížení pro unární operátory, jako například + a -, musíte použít vlnovku (~) v operator-symbol označíte, že provozovatel je unárním operátorem a binární operátor, jak je znázorněno na následující deklaraci.
static member (~-) (v : Vector)
Následující kód ilustruje třída vector, která má pouze dva operátory, jeden pro Unární minus a jeden pro násobení pomocí skalární.V tomto příkladu jsou dva přetížení pro skalární násobení potřebné vzhledem k tomu, že hospodářský subjekt musí pracovat bez ohledu na pořadí, ve kterém se zobrazují vektorový a skalární.
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())
Vytváření nových operátorů
Můžete použít přetížení standardní operátory, ale můžete také vytvořit nové hospodářské subjekty z řad určité znaky.Allowed operator characters are !, %, &, *, +, -, ., /, <, =, >, ?, @, ^,|, and ~.~ Znak má zvláštní význam provádění unární operátor hodnotu a není součástí operátor sekvenci znaků.Ne všechny operátory lze provést unární, je popsán v předpony a operátory Infix dále v tomto tématu.
V závislosti na posloupnost přesné znaků, které používáte bude mít váš operátor přednost a asociativita operátorů.Asociativita operátorů můžete buď zleva doprava nebo zprava doleva a používá se při každém operátorů stejnou úroveň priority se zobrazují v pořadí bez závorek.
Znak operátoru . neovlivňuje prioritu, takže například, pokud chcete definovat vlastní verzi násobení, který má stejnou přednost a asociativita operátorů jako obyčejný násobení, můžete vytvořit operátory, jako .*.
Tabulka, která ukazuje přednosti všech operátorů v F# lze nalézt v Referenční dokumentace symbolů a operátorů (F#).
Názvy přetíženého operátoru
Když kompilátor F# zkompiluje výraz operátor, generuje metodu s názvem generovány kompilátoru pro tento operátor.Toto je název, který se zobrazuje ve zprostředkující jazyk Microsoft (MSIL) pro metodu a také v reflexi a technologie IntelliSense.Obvykle není nutné používat tyto názvy v kódu F#.
V následující tabulce jsou uvedeny standardní operátory a jejich odpovídající generovány 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 |
Další kombinace operátoru znaky, které zde nejsou uvedeny jako operátory lze použít a názvy, které jsou vytvořeny zřetězením názvy jednotlivých znaků z následující tabulky.Například +! becomes op_PlusBang.
Operátor znak |
Název |
---|---|
> |
Greater |
< |
Less |
+ |
Plus |
- |
Minus |
* |
Multiply |
/ |
Divide |
= |
Equals |
~ |
Twiddle |
% |
Percent |
. |
Dot |
& |
Amp |
| |
Bar |
@ |
At |
^ |
Hat |
! |
Bang |
? |
Qmark |
( |
LParen |
, |
Comma |
) |
RParen |
[ |
LBrack |
] |
RBrack |
Předpona a zaváděcí operátory
Předpona se očekává, že provozovatelé umístit před operand nebo operandy, podobně jako funkce.Infix se očekává, že provozovatelé umístit mezi dva operandy.
Pouze některé operátory lze používat jako předponové operátory.Některé operátory jsou vždy předponové operátory, ostatní mohou být zaváděcí nebo předponu a zbývající jsou vždy infix operátory.Hospodářské subjekty, které začínají !, s výjimkou !=a operátor ~, nebo opakované sekvence~, jsou vždy předponové operátory.The operators +, -, +., -., &, &&, %, and %% can be prefix operators or infix operators.Rozlišovat předponu verze těchto operátorů ze zaváděcí verze přidáním ~ na začátku předpona operátor, pokud je definována.~ Nebude použito, pokud použijete operátor, pouze pokud je definována.
Příklad
Následující kód ukazuje použití přetěžování implementovat typ zlomku.Zlomek je reprezentován Čitatel a jmenovatel.Funkce hcf se používá k určení společného faktor nejvyšší, který se používá ke snížení zlomky.
// 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())
Operátory na globální úrovni
Můžete také definovat operátory 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ýstup ve výše uvedeném kódu je 12.
Vzhledem k tomu, že pravidla oboru pro F# diktovat, že nově definovaný operátorů přednost vestavěných operátorů můžete předefinovat běžné aritmetické operátory tímto způsobem.
Klíčové slovo inline se často používá s globální hospodářské subjekty, které jsou často malé funkce, které jsou nejlépe integrovat do volající kód.Vložené funkce vytváření operátor také jim umožňuje pracovat s parametry typu staticky vyřešen vyrábět staticky přeložit obecný kód.Další informace naleznete v tématu Vložené funkce (F#) a Statisticky vyřešené parametry typu (F#).