Я ожидал, что система сообщит о несоответствии протокола, но это не так! Почему? - PullRequest
2 голосов
/ 05 марта 2020

Я использую версию XCode 11.3.1 (11C504)

Я пытаюсь создать обобщенную c функцию в Swift, которая отклоняет свой параметр, если такой параметр не является необязательным.

В следующем коде я ожидал, что система сообщит об ошибках во всех вызовах onlyCallableByAnOptable(), совершенных внутри test(), поскольку ни один из них не обеспечивает необязательное значение в качестве параметра.

Однако система сообщает о непротокольном соответствии, только если я удаляю расширение Optional, соответствующее Optable!

Для меня это означает, что система рассматривает любые значения как Optional, независимо от того,

Я что-то не так делаю?

(Кстати, следующий код раньше работал, как и ожидалось, в более ранних версиях Swift. Я только недавно обнаружил, что он перестал работать, потому что пропускал не-1031 * go. )

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

Ответы [ 2 ]

1 голос
/ 05 марта 2020

Поскольку вы сделали все Optional соответствия Optable и используете синтаксис if let, чтобы развернуть результат вызова в onlyCallableByAnOptable (что означает, что тип возвращаемого значения должен быть своего рода Optional, что означает, что параметр также должен быть того же типа Optional, поскольку и параметр, и тип возвращаемого значения имеют тип T в вашем методе generi c), Swift выводит типы, передаваемые как UIColor?, String? и Int? (неявно заключая их в Optional с) вместо UIColor, String и Int.

0 голосов
/ 05 марта 2020

Я тот, кто написал этот вопрос.

Я пытался создать обобщенную c функцию в Swift, которая отклоняла бы ее параметр, если такой параметр не является Optional.

Как указывало @ TylerTheCompiler , используя мою первоначальную реализацию (в вопросе), Swift выводил тип T (используется в onlyCallableByAnOptable()), основываясь на полном контексте вызов, а не только по типу значения, предоставленного в качестве параметра для него, поэтому выводим T как Optional.

Ради помощи другим, которые могут пытаться достичь того же, что и У меня было следующее решение моей проблемы:

Все вызовы onlyCallableByAnOptable(...) теперь корректно приводят к ошибкам из-за непротокольного соответствия.

Ошибки типа: Argument type 'UIColor' does not conform to expected type 'Optable'

Если кто-нибудь знает о более простом решении, пожалуйста, опубликуйте его как ответ на: Как создать универсальную c функцию в Swift, который отклонит данный параметр, если он не является 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)") 
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...