Udostępnij za pośrednictwem


Przeładowanie operatora (F#)

W tym temacie opisano sposób przeciążać operatory arytmetyczne w klasie lub typu rekordu, a na poziomie globalnym.

// 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

Uwagi

In the previous syntax, the operator-symbol is one of +, -, *, /, =, and so on.parameter-list Określa argumenty w kolejności pojawiają się w zwykłej składni dla tego operatora.method-body Konstrukcje wartość wynikową.

Overloads operator dla operatorów muszą być statyczne.Operator overloads operatory jednoargumentowe, takich jak + i -, należy użyć znaku tyldy (~) w operator-symbol wskazuje, że operator jest operator jednoargumentowy a nie operatora binarnego, jak pokazano w następującej deklaracji.

static member (~-) (v : Vector)

Poniższy kod ilustruje klasy vector, która ma tylko dwa operatory dla minus (jednoargumentowy) i jeden dla mnożenia przez wartość skalarną.W przykładzie dwa przeciążeń dla mnożenia skalarne są potrzebne, ponieważ operator musi działać niezależnie od kolejności, w jakiej pojawiają się wektora i skalarnej.

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())

Tworzenie nowych podmiotów gospodarczych

Może doprowadzić do przeciążenia standardowych operatorów, ale można również tworzyć nowe podmioty gospodarcze z sekwencji numerów określonych znaków.Allowed operator characters are !, %, &, *, +, -, ., /, <, =, >, ?, @, ^,|, and ~.~ Charakter ma specjalne znaczenie dokonywania Jednoargumentowy operator, a nie jest częścią sekwencji znaków operatora.Nie wszystkie podmioty gospodarcze mogą być wykonane jednoargumentowe, jak opisane w prefiksu i Operatorzy Wrostek później w tym temacie.

Sekwencję znaków dokładne, których używasz, w zależności od operatora sieci mają pewne priorytet i łączność.Zespolenie albo lewej do prawej lub od prawej do lewej i jest używany zawsze, gdy podmioty gospodarcze na tym samym poziomie priorytetu pojawiają się w sekwencji bez nawiasów.

Znak operatora . nie wpływa na pierwszeństwo, tak aby, na przykład, jeśli chcesz zdefiniować swoją własną wersję mnożenia, która ma sam priorytet i łączność jako zwykłe mnożenie, można utworzyć operatorów takich jak .*.

Tabela, która zawiera priorytet wszystkich podmiotów gospodarczych w F# można znaleźć w Odwołanie do symbolu i operatora (F#).

Przeciążony Operator nazwy

Kiedy kompilator F# kompiluje wyrażenia operatora, generuje metodę o nazwie generowanych przez kompilator dla tego operatora.Jest to nazwa pojawiająca się w języka Microsoft intermediate language (MSIL) dla metody i odbicie i technologii IntelliSense.Zazwyczaj nie trzeba używać tych nazw w kodzie F#.

W poniższej tabeli przedstawiono standardowych operatorów i odpowiednie generowane nazwy.

Operator

Wygenerowana nazwa

[]

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

Inne kombinacje znaków operatora, które nie są tu wymienione mogą być używane jako operatory i mają nazwy, które składają się poprzez konkatenację nazwy dla poszczególnych znaków z poniższej tabeli.Na przykład +! becomes op_PlusBang.

Znak operatora

Nazwa

>

Greater

<

Less

+

Plus

-

Minus

*

Multiply

/

Divide

=

Equals

~

Twiddle

%

Percent

.

Dot

&

Amp

|

Bar

@

At

^

Hat

!

Bang

?

Qmark

(

LParen

,

Comma

)

RParen

[

LBrack

]

RBrack

Prefiks i Operatorzy Infix

Prefiks operatorzy powinni być umieszczona z przodu operandzie lub operandach, podobnie jak funkcja.Wrostek operatorów oczekuje się być umieszczona między dwa operandy.

Tylko niektóre operatory mogą być używane jako Operatory przedrostkowe.Zawsze są niektóre operatory przedrostkowe operatory, inni mogą być infix lub prefiks, a pozostałe są zawsze infix podmiotów gospodarczych.Podmioty gospodarcze, które zaczynają się !, z wyjątkiem !=oraz operatora ~, lub powtarzające się sekwencje~, są zawsze przedrostkowe operatory.The operators +, -, +., -., &, &&, %, and %% can be prefix operators or infix operators.Rozróżnienie wersja prefiks tych operatorów z wersji infix przez dodanie ~ na początku operatora prefiksu, gdy jest zdefiniowana.~ Nie jest używany, gdy użyć operatora, tylko wtedy, gdy jest on zdefiniowany.

Przykład

Poniższy kod ilustruje użycie przeciążanie do wdrożenia typ ułamka.Ułamek jest reprezentowana przez licznik i mianownik.Funkcja hcf jest używana do określania współczynnika wspólnym najwyższa, która służy zmniejszeniu ułamki.

// 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())
  

Podmioty gospodarcze na poziomie globalnym

Można również zdefiniować podmiotów gospodarczych na poziomie globalnym.Poniższy kod definiuje operator +?.

let inline (+?) (x: int) (y: int) = x + 2*y
printf "%d" (10 +? 1)

Dane wyjściowe powyższy kod jest 12.

Można zmienić definicję regularnych operatorów arytmetycznych w ten sposób, ponieważ regułami zakresu dla F# dyktować, że nowo określonych podmiotów gospodarczych mają pierwszeństwo przed wbudowanych operatorów.

Słowo kluczowe inline jest często używany z globalnych operatorów, które często są małe funkcje, które najlepiej zostały włączone do kodu wywołującego.Wbudowane funkcje operatora podejmowania umożliwia im pracę z parametrami typu statycznie rozwiązane do produkcji statycznie rozpoznać Kod rodzajowy.Aby uzyskać więcej informacji, zobacz Funkcje śródwierszowe (F#) i Statycznie rozwiązywane parametry typu (F#).

Zobacz też

Inne zasoby

Członkowie (F#)