【问题标题】:I expected the system to report non protocol conformance, but it does not! Why?我希望系统报告不符合协议,但事实并非如此!为什么?
【发布时间】:2020-03-05 07:23:01
【问题描述】:

我使用的是 Xcode 版本 11.3.1 (11C504)

我正在尝试在 Swift 中创建一个通用函数,该函数将拒绝它的 参数,除非这样的参数是可选的。

在下面的代码中,我期望系统在test()内部对onlyCallableByAnOptable()的所有调用中报告错误,因为它们都没有提供可选值作为参数。

但是,如果我删除符合OptableOptional 扩展名,系统只会报告不符合协议!

对我来说,这意味着系统将任何和所有值视为Optional,无论如何!

我做错了吗?

(顺便说一下,在早期版本的 Swift 中,以下代码曾经按预期工作。我最近发现它停止工作,因为它让非Optional 通过。)

protocol Optable {
    func opt()
}

func onlyCallableByAnOptable<T>( _ value: T) -> T where T: Optable {
    return value
}

// Comment the following line to get the errors 
extension Optional: Optable { func opt() {} }


class TestOptable {
    static func test() 
    {
        let c = UIColor.blue
        let s = "hi"
        let i = Int(1)

        if let o = onlyCallableByAnOptable(c) { print("color \(o)") }
        //^ expected ERROR: Argument type 'UIColor' does not conform to expected type 'Optable'

        if let o = onlyCallableByAnOptable(s) { print("string \(o)") }
        //^ expected ERROR: Argument type 'String' does not conform to expected type 'Optable'

        if let o = onlyCallableByAnOptable(i) { print("integer \(o)") }
        //^ expected ERROR: Argument type 'Int' does not conform to expected type 'Optable'
    }
}

【问题讨论】:

    标签: swift swift-protocols swift-optionals


    【解决方案1】:

    由于您已使所有Optionals 符合Optable,并且您正在使用if let 语法来解开对onlyCallableByAnOptable 的调用结果(这意味着返回类型必须是某种@ 987654325@,这意味着参数也必须与Optional 的类型相同,因为在您的泛型方法中,参数和返回类型都是T 类型),Swift 推断传入的类型为UIColor?String?Int?(隐式将它们包装在 Optionals 中)而不是 UIColorStringInt

    【讨论】:

    • 嗯!...所以它与函数返回类型推断有关!
    • 我希望 swift 仅根据提供的参数而不是基于预期的返回类型(即上下文)来推断类型。有没有简单的方法来实现这一点?
    • 您可以尝试将函数的返回类型更改为T?,如果您总是希望它返回可选类型,例如:func onlyCallableByAnOptable&lt;T&gt;(_ value: T) -&gt; T? where T: Optable。不过,不确定这是否正是您要寻找的。这样做,我会得到你所期望的错误(例如“全局函数'onlyCallableByAnOptable'要求'UIColor'符合'Optable'”等)
    • 好的。不用担心。如果我碰巧找到了一种方法来做我想做的事,我会将其发布在这里作为补充答案。
    • 我添加了一个答案。你怎么看?我是不是太复杂了?
    【解决方案2】:

    我是发布这个问题的人。

    我试图在 Swift 中创建一个会拒绝的通用函数 它的参数,除非这样的参数是Optional

    正如 @TylerTheCompiler 指出的那样,使用我的原始实现(在问题中),Swift 根据调用的完整上下文推断类型 T(在 onlyCallableByAnOptable() 中使用),不仅仅是作为参数提供给它的值的类型,因此推断TOptional

    为了帮助其他可能试图实现与我相同的人,以下是我对我遇到的问题的解决方案。

    所有对onlyCallableByAnOptable(...) 的调用现在由于不符合协议而正确产生错误。

    错误如:Argument type 'UIColor' does not conform to expected type 'Optable'

    如果有人知道更简单的解决方案,请将其发布为答案 收件人:How to create a generic function in Swift that will reject the given parameter unless it is an Optional?

    protocol Optable {
        associatedtype OptableType
        func optionalOptable() -> OptableType?
        func opt()
    }
    
    func onlyCallableByAnOptable<T>( _ value: T) -> T.OptableType? where T: Optable {
        return value.optionalOptable()
    }
    
    
    extension Optional: Optable {
        typealias OptableType = Wrapped //: Wrapped is the type of the element, as defined in Optional
        func opt() {}
        func optionalOptable() -> OptableType? {
            return self
        }
    }
    
    
    class TestOptable {
        static func test()
        {
            let c = UIColor.blue
            let s = "hi"
            let i = Int(1)
    
            if let o = onlyCallableByAnOptable(c) {  // ERROR, as was desired.
                print("color \(o)") 
            }
            if let o = onlyCallableByAnOptable(s) {  // ERROR, as was desired.
                print("string \(o)") 
            }
            if let o = onlyCallableByAnOptable(i) {  // ERROR, as was desired.
                print("integer \(o)") 
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-10
      • 1970-01-01
      相关资源
      最近更新 更多