Поделиться через


Методы (F#)

Метод — это функция, связанная с типом. В объектно-ориентированном программировании методы используются для предоставления и реализации поведения объектов и типов.

// Instance method definition.
[ attributes ]
member [inline] self-identifier.method-name parameter-list [ : return-type ]=
    method-body

// Static method definition.
[ attributes ]
static member [inline] method-name parameter-list [ : return-type ]=
    method-body

// Abstract method declaration or virtual dispatch slot.
[ attributes ]
abstract member self-identifier.method-name : type-signature

// Virtual method declaration and default implementation.
[ attributes ]
abstract member self-identifier.method-name : type-signature
[ attributes ]
default member self-identifier.method-name parameter-list[ : return-type ] =
    method-body

// Override of inherited virtual method.
[ attributes ]
override member self-identifier.method-name parameter-list [ : return-type ]=
    method-body

Заметки

В предыдущей синтаксической конструкции присутствует несколько форм объявления и определения методов. В телах длинных методов после знака равенства (=) ставится разрыв строки, и все тело метода записывается с отступом.

К любому объявлению метода могут быть применены атрибуты. Они записываются перед синтаксической конструкцией определения метода, обычно на отдельной строке. Дополнительные сведения см. в разделе Атрибуты (F#).

Методы могут быть помечены ключевым словом inline. Сведения о ключевом слове inline см. в разделе Встроенные функции (F#).

В пределах типа можно рекурсивно использовать невстроенные методы; необходимость в явном использовании ключевого слова rec отсутствует.

Методы экземпляра

Методы экземпляра объявляются с помощью ключевого слова member и параметра self-identifier, после которого ставится точка (.), и имени метода и параметров. Как и в случае привязок let, список параметров parameter-list может представлять собой шаблон. Как правило, параметры метода заключаются в круглые скобки в форме кортежа; именно так выглядят в языке F# методы, созданные на других языках платформы .NET Framework. Однако распространена также каррированная форма (параметры, разделенные пробелами); кроме того, поддерживаются и другие шаблоны.

Следующий пример иллюстрирует определение и использование неабстрактного метода экземпляра.

type SomeType(factor0: int) =
   let factor = factor0
   member this.SomeMethod(a, b, c) =
      (a + b + c) * factor

   member this.SomeOtherMethod(a, b, c) =
      this.SomeMethod(a, b, c) * factor

Внутри методов экземпляров не следует использовать собственный идентификатор для доступа к полям, определенным с помощью привязок let. Для доступа к другим членам и свойствам собственный идентификатор используется.

Статические методы

Ключевое слово static позволяет указать, что метод может вызываться без экземпляра и не связан с экземпляром объекта. В противном случае методы являются методами экземпляра.

В примере в следующем разделе показаны поля, объявленные с помощью ключевого слова let, члены-свойства, объявленные с помощью ключевого слова member, и статический метод, объявленный с помощью ключевого слова static.

Следующий пример иллюстрирует определение и использование статических методов. Предполагается, что определения этих методов находятся в классе SomeType из предыдущего раздела.

static member SomeStaticMethod(a, b, c) =
   (a + b + c)

static member SomeOtherStaticMethod(a, b, c) =
   SomeType.SomeStaticMethod(a, b, c) * 100

Абстрактные и виртуальные методы

Ключевое слово abstract указывает, что метод имеет виртуальную ячейку отправки и может не иметь определения в классе. Виртуальная ячейка отправки — это запись во внутренней таблице функций, используемой во время выполнения для поиска вызовов виртуальных функций в объектно-ориентированном типе. Механизм виртуальной отправки — это механизм, реализующий полиморфизм, важную особенность объектно-ориентированного программирования. Класс, имеющий хотя бы один абстрактный метод без определения, является абстрактным классом, что означает, что экземпляры этого класса созданы быть не могут. Дополнительные сведения об абстрактных классах см. в разделе Абстрактные классы (F#).

Определения абстрактных методов не содержат тела метода. Вместо этого после имени метода ставится двоеточие (:) и сигнатура типов для данного метода. Сигнатура типов метода идентична той, которая отображается IntelliSense, если задержать указатель мыши на имени метода в редакторе кода Visual Studio, за тем исключением, что она не содержит имен параметров. Сигнатуры типов также отображаются интерпретатором (fsi.exe) при работе в интерактивном режиме. Сигнатура типов метода образуется перечислением типов параметров, за которыми следует возвращаемый тип, с соответствующими символами-разделителями. Каррированные параметры разделяются символом ->, а кортежные параметры — символом *. Возвращаемое значение всегда отделяется от аргументов символом ->. Можно использовать круглые скобки для группирования сложных параметров (например, когда параметром является тип функции) или для указания того, что кортеж следует рассматривать как один параметр, а не как два параметра.

Абстрактным методам также можно давать определения по умолчанию, добавляя определение в класс с использованием ключевого слова default, как показано в блоке синтаксиса этом разделе. Абстрактный метод, имеющий определение в том же классе, эквивалентен виртуальному методу в других языках платформы .NET Framework. Вне зависимости от того, существует ли определение ключевое слово abstract создает новую ячейку отправки в таблице виртуальных функций для класса.

Вне зависимости от того, реализует ли базовый класс свои абстрактные методы, производные классы могут предоставлять реализации абстрактных методов. Для реализации абстрактного метода в производном классе нужно определить в производном классе метод с теми же именем и сигнатурой, используя, в отличие от базового класса, ключевое слово override или default, и записать тело метода. Ключевые слова override и default означают в точности одно и то же. Используйте ключевое слово override, если новый метод переопределяет реализацию базового класса; используйте ключевое слово default при создании реализации в том же классе, в котором содержится первоначальное абстрактное объявление. Не используйте ключевое слово abstract для метода, реализующего метод, объявленный в базовом классе как абстрактный.

Следующий пример иллюстрирует абстрактный метод Rotate, имеющий реализацию по умолчанию (эквивалент виртуального метода платформы .NET Framework).

type Ellipse(a0 : float, b0 : float, theta0 : float) =
    let mutable axis1 = a0
    let mutable axis2 = b0
    let mutable rotAngle = theta0
    abstract member Rotate: float -> unit
    default this.Rotate(delta : float) = rotAngle <- rotAngle + delta

Следующий пример иллюстрирует производный класс, переопределяющий метод базового класса. В данном случае переопределение изменяет поведение так, что метод ничего не делает.

type Circle(radius : float) =
    inherit Ellipse(radius, radius, 0.0)
     // Circles are invariant to rotation, so do nothing.
    override this.Rotate(_) = ()

Перегруженные методы

Перегруженные методы — это методы, имеющие идентичные имена для данного типа, но разные аргументы. В F# вместо перегруженных методов обычно используются необязательные аргументы. Тем не менее, перегруженные методы в языке разрешены — при условии, что аргументы имеют кортежную форму, не каррированную форму.

Пример: свойства и методы

Следующий пример содержит тип с примерами полей, закрытых функций, свойств и статического метода.

type RectangleXY(x1 : float, y1: float, x2: float, y2: float) =
    // Field definitions.
    let height = y2 - y1
    let width = x2 - x1
    let area = height * width
    // Private functions.
    static let maxFloat (x: float) (y: float) =
      if x >= y then x else y
    static let minFloat (x: float) (y: float) =
      if x <= y then x else y
    // Properties.
    // Here, "this" is used as the self identifier,
    // but it can be any identifier.
    member this.X1 = x1
    member this.Y1 = y1
    member this.X2 = x2
    member this.Y2 = y2
    // A static method.
    static member intersection(rect1 : RectangleXY, rect2 : RectangleXY) =
       let x1 = maxFloat rect1.X1 rect2.X1
       let y1 = maxFloat rect1.Y1 rect2.Y1
       let x2 = minFloat rect1.X2 rect2.X2
       let y2 = minFloat rect1.Y2 rect2.Y2
       let result : RectangleXY option =
         if ( x2 > x1 && y2 > y1) then
           Some (RectangleXY(x1, y1, x2, y2))
         else
           None
       result

// Test code.
let testIntersection =
    let r1 = RectangleXY(10.0, 10.0, 20.0, 20.0)
    let r2 = RectangleXY(15.0, 15.0, 25.0, 25.0)
    let r3 : RectangleXY option = RectangleXY.intersection(r1, r2)
    match r3 with
    | Some(r3) -> printfn "Intersection rectangle: %f %f %f %f" r3.X1 r3.Y1 r3.X2 r3.Y2
    | None -> printfn "No intersection found."

testIntersection

См. также

Основные понятия

Члены (F#)

Журнал изменений

Дата

Журнал

Причина

Апрель 2011

Удален встроенный модификатор из синтаксиса для виртуальных методов.

Исправление ошибки содержимого.