You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何让协议方法在特定结构体中置灰不可用?

Swift 中实现协议方法在特定类型中置灰提示的方案

问题背景

我编写了如下Swift代码,希望实现:让GeneralArithmetic协议中的unwrap()方法在特定结构体(如const)中呈现置灰带红色感叹号的不可用状态(类似废弃方法的提示效果),而在negate等结构体中可正常调用。当前const的unwrap()会抛出错误,但我希望达到视觉上的置灰提示效果。此外还有一个需接收GeneralArithmetic类型参数的evalExp函数。

原始代码

enum UnwrapError: Error {
    case notApplicable(String)
}

protocol GeneralArithmetic {
    func unwrap() throws -> GeneralArithmetic
}

protocol Arithmetic: GeneralArithmetic {
    func evaluate() -> Int
}

protocol ArithmeticBoolean: GeneralArithmetic {
    func evaluate () -> Bool
}

struct const: Arithmetic, CustomStringConvertible {
    let value: Int
    
    init(_ value: Int) {
        self.value = value
    }
    
    func evaluate() -> Int {
        return value
    }
    
    func unwrap() throws -> GeneralArithmetic {
        throw UnwrapError.notApplicable("Available: evaluate()")
    }
    
    var description: String {
        return "const(\(value))"
    }
}

struct negate: Arithmetic, CustomStringConvertible {
    let exp: Arithmetic
    
    init(_ exp: Arithmetic) {
        self.exp = exp
    }
    
    func evaluate() -> Int {
        return -exp.evaluate()
    }
    
    func unwrap() throws -> GeneralArithmetic {
        return exp
    }
    
    var description: String {
        return "negate(\(exp))"
    }
}

struct add: Arithmetic, CustomStringConvertible {
    <#...#>
}
struct multiply: Arithmetic, CustomStringConvertible {
    <#...#>
}
struct bool: ArithmeticBoolean, CustomStringConvertible {
    <#...#>
}

// Error: UnwrapError.notApplicable("Available: evaluate()")
let result = try const(5).unwrap()

// const(5)
let result2 = try negate(const(5)).unwrap()

// 补充的evalExp函数
func evalExp(_ e: GeneralArithmetic) -> const {
    <#...#>
}

解决方案

一、实现置灰提示效果:使用@available标记废弃

Swift的@available属性可以标记方法为废弃,在Xcode中会自动呈现置灰+红色感叹号的提示,完全符合需求。只需在const结构体的unwrap()方法上添加该标记,并自定义提示信息即可。

修改后的const结构体代码:

struct const: Arithmetic, CustomStringConvertible {
    let value: Int
    
    init(_ value: Int) {
        self.value = value
    }
    
    func evaluate() -> Int {
        return value
    }
    
    @available(*, deprecated, message: "请使用 evaluate() 替代")
    func unwrap() throws -> GeneralArithmetic {
        throw UnwrapError.notApplicable("Available: evaluate()")
    }
    
    var description: String {
        return "const(\(value))"
    }
}

此时调用const(5).unwrap()时,Xcode会将该方法置灰,鼠标悬停会显示设置的提示信息,同时保留原有的运行时抛出错误的逻辑。

二、更优雅的类型安全方案:拆分协议

如果希望从编译层面就避免错误调用,而不是仅靠提示和运行时错误,可以重构协议结构,将unwrap()从GeneralArithmetic中剥离,单独定义一个支持解包的协议:

enum UnwrapError: Error {
    case notApplicable(String)
}

// 基础通用算术协议,不包含unwrap方法
protocol GeneralArithmetic {}

// 数值算术协议,继承自通用协议
protocol Arithmetic: GeneralArithmetic {
    func evaluate() -> Int
}

// 布尔算术协议,继承自通用协议
protocol ArithmeticBoolean: GeneralArithmetic {
    func evaluate () -> Bool
}

// 单独定义可解包协议,仅让需要的类型遵循
protocol Unwrappable: GeneralArithmetic {
    func unwrap() throws -> GeneralArithmetic
}

struct const: Arithmetic, CustomStringConvertible {
    let value: Int
    
    init(_ value: Int) {
        self.value = value
    }
    
    func evaluate() -> Int {
        return value
    }
    
    var description: String {
        return "const(\(value))"
    }
}

struct negate: Arithmetic, Unwrappable, CustomStringConvertible {
    let exp: Arithmetic
    
    init(_ exp: Arithmetic) {
        self.exp = exp
    }
    
    func evaluate() -> Int {
        return -exp.evaluate()
    }
    
    func unwrap() throws -> GeneralArithmetic {
        return exp
    }
    
    var description: String {
        return "negate(\(exp))"
    }
}

// evalExp函数依然接收GeneralArithmetic类型,内部可通过类型判断处理不同情况
func evalExp(_ e: GeneralArithmetic) -> const {
    if let unwrappable = e as? Unwrappable {
        // 处理可解包的表达式逻辑
        do {
            let unwrapped = try unwrappable.unwrap()
            // 继续处理解包后的内容
        } catch {
            // 处理错误
        }
    }
    if let arithmetic = e as? Arithmetic {
        // 直接求值并返回const实例
        return const(arithmetic.evaluate())
    }
    // 默认返回值,可根据业务调整
    return const(0)
}

这种方案的优势:

  • 编译层面就阻止了const、bool等类型调用unwrap(),彻底避免运行时错误
  • 代码语义更清晰,哪些类型支持解包一目了然
  • 符合Swift的类型安全设计理念

总结

  • 若仅需要视觉提示效果,使用@available标记废弃是最快的实现方式
  • 若追求类型安全和代码可维护性,拆分协议重构是更合适的长期方案

内容的提问来源于stack exchange,提问作者Adrian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 08:13:26