Swift 类型转换

Swift 中的类型转换(Type Casting)用于在继承层次结构中检查和转换实例的类型,主要用于:

  • 检查对象是否属于某个类或协议
  • 将父类引用转换为子类(向下转型)
  • 处理 Any / AnyObject 容器
  • 安全地调用特定类型的方法

一、核心关键字

关键字用途
is类型检查,返回 Bool
as?可选转换(failable),返回 Optional
as!强制转换(force unwrap),失败时崩溃
as向上转型(upcast),100% 安全

二、基础示例

class Animal {
    func makeSound() { print("...") }
}

class Dog: Animal {
    func bark() { print("Woof!") }
}

class Cat: Animal {
    func meow() { print("Meow!") }
}

// 多态数组
let pets: [Animal] = [Dog(), Cat(), Dog()]

// 1. 类型检查(is)
for pet in pets {
    if pet is Dog {
        print("这是一只狗")
    } else if pet is Cat {
        print("这是一只猫")
    }
}

// 2. 可选转换(as?)
for pet in pets {
    if let dog = pet as? Dog {
        dog.bark()  // 安全调用
    } else if let cat = pet as? Cat {
        cat.meow()
    }
}

三、as vs as? vs as!

写法说明安全适用场景
as向上转型(子 → 父)100% 安全Dog() as Animal
as?可选向下转型安全运行时不确定类型
as!强制向下转型危险100% 确定类型
let dog = Dog()
let animal: Animal = dog as Animal    // 向上转型,安全
let backToDog = animal as? Dog        // 可选向下转型 → Dog?
let forceDog = animal as! Dog         // 强制 → 崩溃风险

四、与 AnyAnyObject 配合

Any:可以是任意类型(包括结构体、枚举、函数)

let mixed: [Any] = [1, "hello", Dog(), 3.14, { print("closure") }]

for item in mixed {
    switch item {
    case let num as Int:
        print("整数: \(num)")
    case let str as String:
        print("字符串: \(str)")
    case let dog as Dog:
        dog.bark()
    case let closure as () -> Void:
        closure()
    default:
        print("其他: \(item)")
    }
}

AnyObject:仅限类实例(引用类型)

let objects: [AnyObject] = [Dog(), Cat(), NSString()]
for obj in objects {
    if let dog = obj as? Dog {
        dog.bark()
    }
}

五、as 向上转型(Upcasting)

func playWith(animal: Animal) {
    animal.makeSound()
}

let dog = Dog()
playWith(animal: dog as Animal)  // 自动推导可省略 as

六、模式匹配中的类型转换

for pet in pets {
    switch pet {
    case let dog as Dog:
        dog.bark()
    case is Cat:
        print("猫不叫")
    default:
        break
    }
}

七、协议类型转换

protocol Flyable {
    func fly()
}

class Bird: Animal, Flyable {
    func fly() { print("飞翔") }
}

let bird = Bird()
if let flyer = bird as? Flyable {
    flyer.fly()
}

// 检查是否遵守协议
if bird is Flyable {
    print("会飞")
}

八、运行时类型信息(type(of:)

print(type(of: dog))     // Dog
print(type(of: animal))  // Animal(动态类型仍是 Dog)

九、常见错误写法

错误正确
animal as Dog(父不能转子)animal as? Dog
as! 用于不确定类型as? + if let
Any 中用 as? Int 检查值类型正确

十、完整实战:JSON 解析 + 类型转换

let json: Any = [
    "name": "Tom",
    "age": 25,
    "pets": [
        ["type": "dog", "name": "旺财"],
        ["type": "cat", "name": "咪咪"]
    ]
]

if let dict = json as? [String: Any],
   let name = dict["name"] as? String,
   let pets = dict["pets"] as? [[String: String]] {

    print("主人: \(name)")

    for pet in pets {
        if let type = pet["type"], let petName = pet["name"] {
            switch type {
            case "dog":
                print("狗: \(petName)")
            case "cat":
                print("猫: \(petName)")
            default:
                break
            }
        }
    }
}

最佳实践总结

场景推荐写法
父类 → 子类(不确定)as? + if let
子类 → 父类as(可省略)
强制转换(确定)as!(慎用)
多类型容器Any + switch + as
协议检查is / as?
避免崩溃永远不要滥用 as!

常见面试题

  1. isas? 的区别?
    is:检查类型,返回 Bool
    as?:尝试转换,返回 Optional
  2. 以下代码会崩溃吗?
let animal: Animal = Dog()
let cat = animal as! Cat

会崩溃Dog 不能强制转为 Cat

  1. AnyAnyObject 区别?
    Any:任意类型
    AnyObject:仅类实例
  2. 如何安全地从 Any 中取出 Int
if let num = value as? Int { ... }
  1. 为什么 animal as? Dog 成功,但 type(of: animal) 仍是 Animal
    → 编译时类型是 Animal,运行时是 Dog(动态派发)

小技巧

// 1. 链式可选转换
let dogName = (animal as? Dog)?.bark()

// 2. where 子句过滤
for case let dog as Dog in pets where dog.name == "旺财" {
    print(dog)
}

// 3. 自定义转换运算符(高级)
precedencegroup CastPrecedence {
    associativity: left
    higherThan: AssignmentPrecedence
}

infix operator ~> : CastPrecedence
func ~> <T, U>(value: T, type: U.Type) -> U? {
    return value as? U
}

let num = mixed[0] ~> Int.self  // Optional(1)

// 4. 安全强制转换宏(Swift 5.9+)
@available(*, unavailable, message: "Use as? instead")
func forceCast<T, U>(_ value: T) -> U { fatalError() }

高级话题(可继续提问)

  • 动态派发 vs 静态派发
  • 类型擦除(Type Erasure)
  • anysome 关键字(Swift 5.7+)
  • 反射与 Mirror
  • 自定义类型转换协议

需要 SwiftUI 中类型转换实战泛型 + 类型转换设计模式,或 性能对比?欢迎继续提问!

文章已创建 2481

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部