Видеокурсы по изучению языка программирования Swift. Подробнее

Операторные методы

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

Классы и структуры могут предоставлять свои собственные реализации существующих операторов. Действие переопределения оператора известно как перегрузка существующего оператора.

Пример ниже отображает как можно реализовать арифметический оператор сложения (+) для пользовательской структуры. Арифметический оператор сложения является бинарным оператором, потому что он оперирует с двумя операндами, то есть он является инфиксным, потому как вставляется между двумя операндами.

Пример определяет структуру Vector2D для двухмерного вектора положения (x, y), за которой идет операторная функция, которая добавляет друг другу экземпляры структуры Vector2D:

struct Vector2D {
    var x = 0.0, y = 0.0
}
 
extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
}

Операторная метод определен как метод типа Vector2D с именем метода, которое совпадает с именем оператора, который перегружают (+). Так как сложение не является неотъемлемой частью поведения вектора, метод типа определен в расширении нашего Vector2D, а не в основной структуре Vector2D. Так как арифметический оператор сложения является бинарным оператором, то этот оператор принимает два параметра типа Vector2D и возвращает единственное выходное значение, которое тоже имеет тип Vector2D.

В этой реализации входные параметры имеют имена left и right, для отображения экземпляров Vector2D, которые будут по левую и по правую сторону от оператора +. Функция возвращает новый экземпляр Vector2D, x и y которого инициализированы суммой свойств x и y из двух экземпляров Vector2D, которые были добавлены друг другу.

Метод типа может использоваться как инфиксный оператор между существующими экземплярами Vector2D:

let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector является экземпляром Vector2D, который имеет значения (5.0, 5.0)

Этот пример складывает два вектора вместе (3.0, 1.0) и (2.0, 4.0) для создания вектора (5.0, 5.0), который нарисован ниже:

Префиксные и постфиксные операторы

Пример, отображенный выше, демонстрирует пользовательскую реализацию бинарного инфиксного оператора. Классы и структуры так же могут обеспечивать реализацию стандартных унарных операторов. Унарные операторы работают с одним операндом. Они бывают префиксными, если они предшествуют их операнду (например, -a) или постфиксными, если они следуют за операндом (например b!).

Вы реализуете префиксный или постфиксный унарный оператор при помощи модификаторов prefix или postfix перед ключевым словом func, когда объявляете операторную функцию:

extension Vector2D {
    static prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D(x: -vector.x, y: -vector.y)
    }
}

Пример выше реализует унарный оператор (-a) для экземпляров Vector2D. Оператор унарного минуса является префиксным оператором, таким образом эта функция должна быть модифицирована при помощи prefix модификатора.

Для простых числовых значений оператор унарного минуса конвертирует положительные числа в их негативный эквивалент и наоборот. Соответствующая реализация для экземпляров Vector2D проводит операции и на x, и на y свойствах:

let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative - экземпляр Vector2D со значениями (-3.0, -4.0)
let alsoPositive = -negative
// alsoPositive - экземпляр Vector2D со значениями (3.0, 4.0)

Составные операторы присваивания

Составные операторы присваивания комбинируют оператор присваивания (=) с другим оператором. Например, оператор сложения-присваивания (+=) комбинирует в себе оператор добавления и оператор присваивания. Вы обозначаете левый входной параметр составного оператора как inout, потому что именно эта величина и будет изменена напрямую изнутри самой операторной функции.

Пример ниже реализует операторную функцию добавления-присваивания для экземпляров Vector2D:

extension Vector2D {
    static func += (left: inout Vector2D, right: Vector2D) {
        left = left + right
    }
}

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

var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original теперь имеет значения (4.0, 6.0)

Заметка

Не такой возможности перегрузить оператор присваивания (=). Только составные операторы могут быть перегружены. Тернарный оператор (a ? b : c) так же не может быть перегружен.

Операторы эквивалентности

Пользовательские классы и структуры не получают дефолтной реализации эквивалентных операторов, известных как “равен чему-то” оператор (==) или “не равен чему-то” (!=). Swift не может угадать, что в конкретном случае может означать “равен” для вашего собственного пользовательского типа, потому что значение слова “равен” зависит от роли, которую играет конкретный тип в вашем коде.

Чтобы использовать операторы эквивалентности для проверки эквивалентности вашего собственного пользовательского типа, предоставьте реализацию для этих операторов тем же самым способом, что и для инфиксных операторов:

extension Vector2D {
    static func == (left: Vector2D, right: Vector2D) -> Bool {
        return (left.x == right.x) && (left.y == right.y)
    }
    static func != (left: Vector2D, right: Vector2D) -> Bool {
        return !(left == right)
    }
}

Пример выше реализует оператор “равен чему-то” (==) для проверки эквивалентности значений двух экземпляров Vector2D. В контексте Vector2D имеет смысл считать, что “равно чему-то” означает, что “оба экземпляра имеют одни и те же значения x и y”, таким образом это является той логикой, которая используется при реализации оператора. Пример так же реализует оператор “не равен чему-то” (!=), который просто возвращает обратный результат оператора “равен чему-то”.

Теперь вы можете использовать эти операторы для проверки того, эквивалентны ли экземпляры Vector2D друг другу или нет:

let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
    print("Эти два вектора эквиваленты.")
}
// Выведет "Эти два вектора эквиваленты."

 

Swift: 
4.0