If you know C++, it’s easy to understand Operator Overload. OC does not support operator overloading, but Swift does.

Overflow operators

A runtime error is thrown when an overflow occurs in Swift’s arithmetic operator.

Example code 1:

print(Int8.min) // Output: -128
print(Int8.max) // Output: 127
print(UInt8.min) // Output: 0
print(UInt8.max) // Output: 255

var a = UInt8.max
a + = 1
print(a)
Copy the code

Int8 can be represented in the range of -128~127, UInt8 can be represented in the range of 0~255. An error is reported when running outside of the representable number range.

Swift has overflow operators to support overflow operations. Common overflow operators: &+, &-, &*

Example code 2:

var a = UInt8.max
a = a & + 1
print(a) // Output: 0

var b = UInt8.min
b = b & - 2
print(b) // Output: 254
Copy the code

When data overflows, the overflow operator automatically loops through countable ranges.

Official legend:

Operator overloading

Classes, structs, and enumerations can provide custom implementations of existing operators, an operation called operator overloading.

Normal addition:

let v1 = 10
let v2 = 20
let v3 = v1 + v2
Copy the code

If changed to non-basic numerical calculation:

struct Point {
    var x = 0, y = 0
}
let p1 = Point(x: 10, y: 20)
let p2 = Point(x: 20, y: 30)
let p3 = p1 + p2
Copy the code

The compiler does not support this, so operator overloading is required.

2.1. Operator: +

struct Point {
    var x = 0, y = 0
    // The + operator is overloaded
    static func +(p1: Point.p2: Point) -> Point {
        Point(x: p1.x + p2.x, y: p1.y + p2.y)
    }
}

let p1 = Point(x: 10, y: 20)
let p2 = Point(x: 20, y: 30)
let p3 = p1 + p2
print(p3) // Point(x: 30, y: 50)
Copy the code

The + operator overload code can be written outside the structure, but it is usually recommended to write it inside (highly cohesive).

2.2. Operators: minus prefix (operator in front)

static prefix func -(p: Point) -> Point {
    Point(x: -p.x, y: -p.y)
}
let p1 = Point(x: 10, y: 20)
let p2 = -p1
print(p2) // Point(x: -10, y: -20)
Copy the code

2.3. Operator: +=

static func + =(p1: inout Point.p2: Point) {
    p1 = Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
var p1 = Point(x: 10, y: 20)
let p2 = Point(x: 20, y: 30)
p1 + = p2
print(p1) // Point(x: 30, y: 50)
Copy the code

When the += operator is overloaded, the variable on the left of the overloaded function must be inout because the memory of the external variable is being modified. And external variables are declared using var. Since only the memory of the first parameter needs to be modified, the function does not need to return a value.

2.4. Operator: prefix ++

static prefix func ++(p: inout Point) -> Point {
    p + = Point(x: 1, y: 1)
    return p
}
var p1 = Point(x: 10, y: 20)
let p2 = ++p1
print(p2) // Point(x: 11, y: 21)
Copy the code

++ is written before variables: add first, use later

2.5. Operator: ++ after

static postfix func ++(p: inout Point) -> Point {
    let tmp = p
    p + = Point(x: 1, y: 1)
    return tmp
}
var p1 = Point(x: 10, y: 20)
let p2 = p1++
print(p2) // Point(x: 10, y: 20)
Copy the code

++ is written after variables: use first and then add

2.6. Operator: ==

static func = =(p1: Point.p2: Point) -> Bool {
    (p1.x = = p2.x) && (p1.y = = p2.y)
}
let p1 = Point(x: 10, y: 20)
let p2 = Point(x: 20, y: 30)
let isTrue1 = p1 = = p2
print(isTrue1) // Output: false

let p3 = Point(x: 20, y: 30)
let isTrue2 = p2 = = p3
print(isTrue2) // Output: true
Copy the code

To know if two instances are equivalent, the general approach is to follow the Equatable protocol and override the == operator.

2.7. Equatableagreement

public protocol Equatable {
    static func = = (lhs: Self.rhs: Self) -> Bool
}
Copy the code

Sample code:

struct Point: Equatable {
    var x = 0, y = 0
    static func = = (lhs: Self.rhs: Self) -> Bool {
        //
        if lhs.x = = rhs.x && lhs.y = = rhs.y {
            return true
        }
        return false
        / / short
        // lhs.x == rhs.x && lhs.y == rhs.y}}let p1 = Point(x: 10, y: 20)
let p2 = Point(x: 20, y: 30)
let isTrue1 = p1 = = p2
print(isTrue1) // Output: false

let p3 = Point(x: 20, y: 30)
let isTrue2 = p2 = = p3
print(isTrue2) // Output: true
Copy the code

The == operator can be overridden regardless of whether the Equatable protocol is complied with, so why comply with the protocol? Because complying with the protocol directly tells others that the class/struct/enumeration supports the == operator comparison. One other important difference is that it complies with the Equatable protocol, which overloads by default! The = operator, but the custom == operator is not overloaded! = operator.

Swift provides a default Equatable implementation for the following types:

  • There is no enumeration of associated types
enum Answer {
    case wrong
    case right
}
var s1 = Answer.wrong
var s2 = Answer.right
print(s1 = = s2) // Output: false
Copy the code
  • Only have complianceEquatableEnumeration of protocol association types
enum Answer: Equatable {
    case wrong(Int)
    case right
}
var s1 = Answer.wrong(10)
var s2 = Answer.wrong(10)
print(s1 = = s2) // Output: true
Copy the code

If you don’t complyEquatableEnumeration of protocol association types:

  • Only have complianceEquatableA structure for storing properties of a protocol
struct Point: Equatable {
    var x = 0, y = 0
}
let p1 = Point(x: 10, y: 20)
let p2 = Point(x: 20, y: 30)
let isTrue1 = p1 = = p2
print(isTrue1) // Output: false

let p3 = Point(x: 20, y: 30)
let isTrue2 = p2 = = p3
print(isTrue2) // Output: true
Copy the code

2.8. Identity operators= = =,! = =

Reference types compare stored address values for equality (referencing the same object) using the identity operator ===,! == (reference type only).

class Person {}var p1 = Person(a)var p2 = Person(a)print(p1 = = = p2) // Output: false
print(p1 ! = = p2) // Output: true
Copy the code

2.9. Comparableagreement

To compare the size of two instances, the general approach is:

  • Comply with theComparableagreement
  • Override the corresponding operator

Comparable Agreement as officially defined:

public protocol Comparable : Equatable {
    static func < (lhs: Self.rhs: Self) -> Bool
    static func < = (lhs: Self.rhs: Self) -> Bool
    static func > = (lhs: Self.rhs: Self) -> Bool
    static func > (lhs: Self.rhs: Self) -> Bool
}
Copy the code

Sample code:

// If score is equal, age is equal
struct Student : Comparable {
    var age: Int
    var score: Int
    init(age: Int.score: Int) {
        self.age = age
        self.score = score
    }
    static func < (lhs: Student.rhs: Student) -> Bool {
        (lhs.score < rhs.score) || (lhs.score = = rhs.score && lhs.age > rhs.age)
    }
    static func > (lhs: Student.rhs: Student) -> Bool {
        (lhs.score > rhs.score) || (lhs.score = = rhs.score && lhs.age < rhs.age)
    }
    static func < = (lhs: Student.rhs: Student) -> Bool {
        !(lhs > rhs)
    }
    static func > = (lhs: Student.rhs: Student) -> Bool {
        !(lhs < rhs)
    }
}

var stu1 = Student(age: 20, score: 100)
var stu2 = Student(age: 18, score: 98)
var stu3 = Student(age: 20, score: 100)
print(stu1 > stu2) // Output: true
print(stu1 > = stu2) // Output: true
print(stu1 > = stu3) // Output: true
print(stu2 < stu1) // Output: true
print(stu2 < = stu1) // Output: true
print(stu1 < = stu3) // Output: false
Copy the code

3. Custom Operators

All of the above are overloads for existing operators, whereas a custom operator defines an operator that does not already exist.

Custom new operators are declared in the global scope using operator.

Format:

prefix operatorThe prefix operator postfixoperatorThe suffix operator infixoperatorPrefix operator: Priority group PRECEDenceGroup Priority group {associativity: associativity (left)/right/None) higherThan: lowerThan: Who has a lower priority than the assignment:trueHas the same precedence as the assignment operator in optional chain operations}Copy the code

Example code (defines the prefix operator+++) :

prefix operator +++
prefix func +++ (_ i: inout Int) {
    i + = 2
}
var age = 10
+++age
print(age) // Output: 12
Copy the code

Sample code (definition+-Operator and set operator priority) :

infix operator +- : PlusMinusPrecedence
precedencegroup PlusMinusPrecedence {
    associativity: none
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
    assignment: true
}
struct Point {
    var x = 0, y = 0
    static func +- (p1: Point.p2: Point) -> Point {
        Point(x: p1.x + p2.x, y: p1.y - p2.y)
    }
}
var p1 = Point(x: 10, y: 20)
var p2 = Point(x: 5, y: 15)
var p3 = p1 +- p2
print(p3) // Point(x: 15, y: 5)
Copy the code

If setassociativity: noneIf two or more operators are used, an error is reported:

Resolve error:

  1. associativityThe valuesleftorright
  2. Use an operator

The assignment of sample:

class Person {
    var point: Point = Point()}var p: Person? = Person(a)let result = p?.point +- Point(x: 10, y: 20)
print(result!) // Point(x: 10, y: -20)
Copy the code

If the variable p is nil, it does not proceed to the right (the +- operator does not execute); If not nil, the code executes in normal order (the +- operator executes normally).

Priority group parameters:

  • associativityAssociativity has three values:
    • left: Compute from left to right
    • right: Computes from right to left
    • none: Only one operator, multiple operators will report an error (example:a1 + a2 + a3, there are two operators compiling error)
  • higherThan: Which operator has a higher priority than the currently defined operator
  • lowerThan: Which operator has a lower priority than the currently defined operator
  • assignment:trueRepresents the same precedence as the assignment operator in the optional chain operation

Operator priority group description:

Refer to the official document: 1. The operator precedence group description: developer.apple.com/documentati…

2. Advanced operators:Docs.swift.org/swift-book/…

For more articles in this series, please follow our wechat official account [1024 Planet].