扩展 #

一、扩展概述 #

扩展可以为现有的类、结构体、枚举或协议添加新功能。

1.1 扩展能力 #

  • 添加计算属性
  • 添加方法
  • 添加初始化器
  • 添加下标
  • 遵循协议
  • 定义嵌套类型

二、计算属性 #

2.1 添加属性 #

swift
extension Double {
    var km: Double { return self * 1000 }
    var m: Double { return self }
    var cm: Double { return self / 100 }
    var mm: Double { return self / 1000 }
}

let distance = 1.5.km
print("\(distance)米")

let height = 180.cm
print("\(height)米")

2.2 扩展标准库 #

swift
extension String {
    var length: Int {
        return count
    }
    
    var reversed: String {
        return String(self.reversed())
    }
    
    var isNotEmpty: Bool {
        return !isEmpty
    }
}

let text = "Hello"
print(text.length)
print(text.reversed)
print(text.isNotEmpty)

三、方法 #

3.1 实例方法 #

swift
extension Int {
    func times(_ action: () -> Void) {
        for _ in 0..<self {
            action()
        }
    }
    
    func squared() -> Int {
        return self * self
    }
}

5.times {
    print("Hello")
}

print(5.squared())

3.2 可变方法 #

swift
extension Int {
    mutating func square() {
        self = self * self
    }
}

var number = 5
number.square()
print(number)

3.3 类型方法 #

swift
extension String {
    static func random(length: Int) -> String {
        let letters = "abcdefghijklmnopqrstuvwxyz"
        return String((0..<length).map { _ in letters.randomElement()! })
    }
}

print(String.random(length: 10))

四、初始化器 #

4.1 添加初始化器 #

swift
struct Size {
    var width: Double
    var height: Double
}

extension Size {
    init(square side: Double) {
        self.init(width: side, height: side)
    }
}

let square = Size(square: 10)
print("宽: \(square.width), 高: \(square.height)")

4.2 扩展标准类型 #

swift
extension Double {
    init?(fromString string: String) {
        guard let value = Double(string) else {
            return nil
        }
        self = value
    }
}

if let value = Double(fromString: "3.14") {
    print(value)
}

五、下标 #

5.1 添加下标 #

swift
extension String {
    subscript(i: Int) -> String {
        guard i >= 0 && i < count else { return "" }
        let index = self.index(startIndex, offsetBy: i)
        return String(self[index])
    }
    
    subscript(range: Range<Int>) -> String {
        let start = index(startIndex, offsetBy: range.lowerBound)
        let end = index(startIndex, offsetBy: range.upperBound)
        return String(self[start..<end])
    }
}

let text = "Hello"
print(text[0])
print(text[1..<4])

5.2 数组扩展 #

swift
extension Array {
    subscript(safe index: Int) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

let numbers = [1, 2, 3, 4, 5]
print(numbers[safe: 2] ?? 0)
print(numbers[safe: 10] ?? 0)

六、嵌套类型 #

6.1 添加嵌套类型 #

swift
extension Int {
    enum Kind {
        case negative, zero, positive
    }
    
    var kind: Kind {
        switch self {
        case 0: return .zero
        case let x where x > 0: return .positive
        default: return .negative
        }
    }
}

print(5.kind)
print((-3).kind)
print(0.kind)

七、协议遵循 #

7.1 遵循协议 #

swift
struct Person {
    var name: String
    var age: Int
}

extension Person: CustomStringConvertible {
    var description: String {
        return "\(name), \(age)岁"
    }
}

let person = Person(name: "张三", age: 25)
print(person)

7.2 条件遵循 #

swift
extension Array: CustomStringConvertible where Element: CustomStringConvertible {
    var description: String {
        return "[" + map { $0.description }.joined(separator: ", ") + "]"
    }
}

7.3 多协议遵循 #

swift
extension Person: Equatable, Comparable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name && lhs.age == rhs.age
    }
    
    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.age < rhs.age
    }
}

八、实际应用 #

8.1 颜色扩展 #

swift
extension UIColor {
    convenience init(hex: String, alpha: CGFloat = 1.0) {
        var hexFormatted = hex.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        hexFormatted = hexFormatted.replacingOccurrences(of: "#", with: "")
        
        var rgbValue: UInt64 = 0
        Scanner(string: hexFormatted).scanHexInt64(&rgbValue)
        
        self.init(
            red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
            alpha: alpha
        )
    }
}

let color = UIColor(hex: "#FF8000")

8.2 日期扩展 #

swift
extension Date {
    var isToday: Bool {
        return Calendar.current.isDateInToday(self)
    }
    
    var isYesterday: Bool {
        return Calendar.current.isDateInYesterday(self)
    }
    
    var isTomorrow: Bool {
        return Calendar.current.isDateInTomorrow(self)
    }
    
    func format(_ format: String) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = format
        return formatter.string(from: self)
    }
}

let now = Date()
print(now.isToday)
print(now.format("yyyy年MM月dd日"))

8.3 数组扩展 #

swift
extension Array {
    func chunked(into size: Int) -> [[Element]] {
        guard size > 0 else { return [] }
        return stride(from: 0, to: count, by: size).map {
            Array(self[$0..<Swift.min($0 + size, count)])
        }
    }
    
    func unique<T: Hashable>(by keyPath: KeyPath<Element, T>) -> [Element] {
        var seen = Set<T>()
        return filter { seen.insert($0[keyPath: keyPath]).inserted }
    }
}

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(numbers.chunked(into: 3))

九、总结 #

本章学习了Swift扩展:

  • 计算属性:添加属性
  • 方法:添加实例和类型方法
  • 初始化器:添加构造函数
  • 下标:添加下标访问
  • 协议遵循:实现协议

最佳实践:

  • 使用扩展组织代码
  • 扩展标准库增加便利功能
  • 使用扩展分离协议实现
  • 避免过度扩展

下一章,我们将学习高级特性!

最后更新:2026-03-26