I expected the system to report non protocol conformance, but it does not! Why?

巧了我就是萌 提交于 2020-03-22 09:06:39

问题


I am using Xcode Version 11.3.1 (11C504)

I am trying to create a generic function in Swift that will reject its parameter unless such a parameter is Optional.

In the following code, I was expecting the system to report errors in all calls to onlyCallableByAnOptable() made inside test(), because none of them provide an optional value as a parameter.

However, the system only reports non-protocol conformance if I remove the Optional extension that conforms to Optable!

Which to me, it means that the system is regarding any and all values as Optional, regardless!

Am I doing something wrong?

(By the way, the following code used to be working as expected in earlier versions of Swift. I just recently found out that it stopped working, for it was letting a non-Optional go through.)

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'
    }
}

回答1:


Since you've made all Optionals conform to Optable and you are using the if let syntax to unwrap the result of the call to onlyCallableByAnOptable (which means the return type must be some kind of Optional, which means the parameter must also be that same type of Optional because both the parameter and the return type are of type T in your generic method), Swift is inferring the types being passed in as UIColor?, String?, and Int? (implicitly wrapping them in Optionals) instead of UIColor, String and Int.




回答2:


I am the one who posted this question.

I was trying to create a generic function in Swift that would reject its parameter unless such parameter is an Optional.

As @TylerTheCompiler pointed out, using my original implementation (in the question), Swift was inferring type T (used in onlyCallableByAnOptable()), based on the full context of the call, not solely on the type of the value provided as parameter to it, therefore inferring T to be an Optional.

For the sake of helping others who might be trying to achieve the same as I was, the following is my solution to the problem I had.

All calls to onlyCallableByAnOptable(...) now correctly yield errors due to non-protocol conformance.

Errors like: Argument type 'UIColor' does not conform to expected type 'Optable'

If anyone knows of a simpler solution, please do post it as an answer to: 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)") 
        }
    }
}


来源:https://stackoverflow.com/questions/60540076/i-expected-the-system-to-report-non-protocol-conformance-but-it-does-not-why

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!