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. Equatable
agreement
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 compliance
Equatable
Enumeration 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 complyEquatable
Enumeration of protocol association types:
- Only have compliance
Equatable
A 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. Comparable
agreement
To compare the size of two instances, the general approach is:
- Comply with the
Comparable
agreement - 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: none
If two or more operators are used, an error is reported:
Resolve error:
associativity
The valuesleft
orright
- 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:
associativity
Associativity has three values:left
: Compute from left to rightright
: Computes from right to leftnone
: 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 operatorlowerThan
: Which operator has a lower priority than the currently defined operatorassignment
:true
Represents 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].