MST

星途 面试题库

面试题:Swift泛型元编程与类型擦除

假设你正在开发一个通用的数据存储框架,需要支持不同类型的数据存储(如内存存储、文件存储等)。使用Swift泛型元编程技术,设计一个灵活的架构,使得不同的存储类型可以共享通用的操作接口,同时通过类型擦除来避免泛型类型膨胀问题。请给出主要的代码结构和关键实现思路。
26.5万 热度难度
编程语言Swift

知识考点

AI 面试

面试题答案

一键面试

主要代码结构和关键实现思路

  1. 定义通用操作协议:首先定义一个协议,该协议包含所有数据存储都需要支持的通用操作,例如读、写操作。
protocol DataStorageProtocol {
    associatedtype Value
    func write(_ value: Value, forKey key: String)
    func read(forKey key: String) -> Value?
}
  1. 具体存储类型实现:为每种具体的存储类型(如内存存储、文件存储)实现上述协议。
    • 内存存储
class InMemoryStorage<Value>: DataStorageProtocol {
    private var storage: [String: Value] = [:]
    func write(_ value: Value, forKey key: String) {
        storage[key] = value
    }
    func read(forKey key: String) -> Value? {
        return storage[key]
    }
}
- **文件存储**:
class FileStorage<Value>: DataStorageProtocol {
    private let filePath: String
    init(filePath: String) {
        self.filePath = filePath
    }
    func write(_ value: Value, forKey key: String) {
        // 实现将value写入文件的逻辑,这里简单示例忽略实际写入细节
        let data = try? JSONEncoder().encode(value)
        try? data?.write(to: URL(fileURLWithPath: filePath))
    }
    func read(forKey key: String) -> Value? {
        // 实现从文件读取value的逻辑,这里简单示例忽略实际读取细节
        guard let data = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else { return nil }
        return try? JSONDecoder().decode(Value.self, from: data)
    }
}
  1. 类型擦除:为了避免泛型类型膨胀,使用类型擦除技术。创建一个 AnyDataStorage 结构体,它包装了遵循 DataStorageProtocol 的具体类型,并通过 eraseToAnyDataStorage 方法来进行类型擦除。
struct AnyDataStorage {
    private let base: AnyDataStorageBase
    init<Value: Any>(_ storage: some DataStorageProtocol where storage.Value == Value) {
        base = AnyDataStorageBaseImpl(storage)
    }
    func write(_ value: Any, forKey key: String) {
        base.write(value, forKey: key)
    }
    func read(forKey key: String) -> Any? {
        return base.read(forKey: key)
    }
}

private protocol AnyDataStorageBase {
    func write(_ value: Any, forKey key: String)
    func read(forKey key: String) -> Any?
}

private class AnyDataStorageBaseImpl<Value: Any, Storage: DataStorageProtocol>: AnyDataStorageBase where Storage.Value == Value {
    private let storage: Storage
    init(_ storage: Storage) {
        self.storage = storage
    }
    func write(_ value: Any, forKey key: String) {
        guard let value = value as? Value else { return }
        storage.write(value, forKey: key)
    }
    func read(forKey key: String) -> Any? {
        return storage.read(forKey: key)
    }
}

extension DataStorageProtocol {
    func eraseToAnyDataStorage() -> AnyDataStorage {
        return AnyDataStorage(self)
    }
}
  1. 使用示例
let inMemory = InMemoryStorage<Int>()
let inMemoryAny = inMemory.eraseToAnyDataStorage()
inMemoryAny.write(10, forKey: "test")
if let result = inMemoryAny.read(forKey: "test") as? Int {
    print(result)
}

let file = FileStorage<Double>(filePath: "test.txt")
let fileAny = file.eraseToAnyDataStorage()
fileAny.write(10.5, forKey: "test")
if let result = fileAny.read(forKey: "test") as? Double {
    print(result)
}

通过上述步骤,实现了一个灵活的架构,不同存储类型共享通用操作接口,同时利用类型擦除解决了泛型类型膨胀问题。