问题
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 Optional
s 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 Optional
s) 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