Udostępnij za pośrednictwem


Przeciążanie (F#)

W tym temacie opisano sposób na przeciążenie operatory arytmetyczne w klasie lub typ rekordu i 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łym składni dla tego operatora.method-body Konstrukcje wartość wynikową.

Overloads operatora dla podmiotów musi być statyczna.Operator overloads operatory jednoargumentowe, takich jak + i -, należy użyć znaku tyldy (~) w operator-symbol aby wskazać, że operator jest operator unarny i binarne operatora, jak pokazano w następującej deklaracji.

static member (~-) (v : Vector)

Poniższy kod ilustruje klasy vector, który ma tylko dwa operatory: jeden dla Negacja jednoargumentowe, a drugi dla mnożenia przez skalarnej.W przykładzie ponieważ operator musi działać niezależnie od kolejności, w jakiej pojawiają się wektorowe i skalarnej potrzebne są dwa overloads dla mnożenia skalarne.

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

Mogą przeciążać standardowe operatory, ale można również utworzyć sekwencje znaków niektórych nowych operatorów.Allowed operator characters are !, %, &, *, +, -, ., /, <, =, >, ?, @, ^,|, and ~.~ Znaków ma specjalne znaczenie dokonywania Jednoargumentowy operator i nie jest częścią sekwencji znaków operatora.Nie wszystkie podmioty gospodarcze mogą ustanowić jednoargumentowe, opisane w prefiksu i Operatorzy Wrostek później w tym temacie.

W zależności od tego, sekwencja znaków dokładne używanego operatora sieci będzie niektórych priorytet i łączność.Łączność, można albo lewej do prawej lub od prawej do lewej i jest używany zawsze, gdy ten sam poziom pierwszeństwa operatorów są wyświetlane w kolejności bez nawiasów.

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

Tabelę przedstawiającą pierwszeństwo operatorów wszystkich F# można znaleźć w Symbol i Operator odniesienia (F#).

Przeciążony Operator nazwy

F# kompilator kompiluje wyrażeniu operatora, generuje metoda, która ma nazwę dla tego operatora generowany przez kompilator.Jest to nazwa wyświetlana w Microsoft intermediate language (MSIL) dla metody i odbicie i IntelliSense.Zwykle nie trzeba używać tych nazw w kodzie F#.

W poniższej tabeli przedstawiono standardowe operatory i odpowiednie generowane nazwy.

Operator

Nazwa wygenerowana

[]

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ą tutaj 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.

Operator znaków

Nazwa

>

Greater

<

Less

+

Plus

-

Minus

*

Multiply

/

Divide

=

Equals

~

Twiddle

%

Percent

.

Dot

&

Amp

|

Bar

@

At

^

Hat

!

Bang

?

Qmark

(

LParen

,

Comma

)

RParen

[

LBrack

]

RBrack

Prefiks i Infiks operatory

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

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

Przykład

Poniższy kod ilustruje wykorzystanie przeciążanie do wykonania typu ułamek.Ułamek jest reprezentowana przez Liczebnik 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 także zdefiniować podmiotom gospodarczym na poziomie globalnym.W poniższym kodzie zdefiniowano operatora +?.

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

Dane wyjściowe z powyższego kodu jest 12.

Ponieważ regułami zakresu dla F# dyktowania, że nowo zdefiniowane operatorzy mają pierwszeństwo przed wbudowanych operatorów, można ponownie zdefiniować regularnych operatory arytmetyczne w ten sposób.

Słowo kluczowe inline jest często używany z operatorami globalnych, które są często małych funkcji, które są najlepiej zintegrowane kod wywołujący.Wbudowane funkcje operator Making umożliwia im pracę z parametrami statycznie rozpoznać typ produkować statycznie rozwiązane Kod rodzajowy.Aby uzyskać więcej informacji, zobacz Wbudowane funkcje (F#) i Statycznie rozwiązane parametrów typu (F#).

Zobacz też

Inne zasoby

Członkowie (F#)