2

我正在使用 Xcode 版本 11.3.1 (11C504)

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

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

Optional但是,如果我删除符合Optable!的扩展名,系统只会报告非协议符合性。

对我来说,这意味着系统将任何和所有值视为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'
    }
}
4

2 回答 2

1

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

于 2020-03-05T07:39:25.290 回答
0

我是发布这个问题的人。

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

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

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

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)") 
        }
    }
}
于 2020-03-05T08:42:24.460 回答