It appears that you can’t extend a generic class/struct with a requirement that a type parameter inherit from a non-protocol:
extension Dictionary where Key : String { … }
The above produces the error “Type ‘Key’ constrained to non-protocol type ‘String’”.
So is there a way I can add a method to a class, where the method depends on one of the type parameters being a specific type? For example, let’s say I want a “concatenatedKeys” method that returns all the Dictionary’s keys concatenated into a string with commas between them.
(The actual reason I’m doing this is more complicated, but it has to do with JSON encoding — JSON dictionary keys have to be strings, so I want to be type-safe and make my encoding methods available only for Dictionary<String, ___>.)
It appears that you can’t extend a generic class/struct with a requirement that a type parameter inherit from a non-protocol:
extension Dictionary where Key : String { … }
The above produces the error “Type ‘Key’ constrained to non-protocol type ‘String’”.
You can't do `Key: String` because `String`, as a struct, cannot have any subtypes. `Key: NSString`, for instance, works.
What you really want to do is say `Key == String`, but this isn't supported right now. (My understanding is that this is basically just an implementation shortcut they took.)
One workaround is to define your own protocol and constrain to that:
protocol _StringType: Hashable {
// Include the String APIs you need to use here.
}
extension String: _StringType {}
extension Dictionary where Key: _StringType { … }
It looks like you can make it work using StringLiteralConvertible. Based on this:
This works:
extension Dictionary where Key: StringLiteralConvertible, Value: Any {
func testMethod() -> String {
return "test"
}
}
var d: [String: Int] = [:]
d["abc"] = 1
print(d.testMethod())
HTH,
Dave Reed
···
On Apr 14, 2016, at 4:58 PM, Jens Alfke via swift-users <swift-users@swift.org> wrote:
It appears that you can’t extend a generic class/struct with a requirement that a type parameter inherit from a non-protocol:
extension Dictionary where Key : String { … }
The above produces the error “Type ‘Key’ constrained to non-protocol type ‘String’”.
So is there a way I can add a method to a class, where the method depends on one of the type parameters being a specific type? For example, let’s say I want a “concatenatedKeys” method that returns all the Dictionary’s keys concatenated into a string with commas between them.
(The actual reason I’m doing this is more complicated, but it has to do with JSON encoding — JSON dictionary keys have to be strings, so I want to be type-safe and make my encoding methods available only for Dictionary<String, ___>.)
You know… if protocols could define which types can implement them, that could be made to be the same thing:
protocol _String {…} `syntax which restricts instances of _String to be a` String
extension Dictionary where Key: _String {…} //Same as "where Key == String”, because that’s the only type allowed to implement _String
Is that worth writing proposal over? Or is just saying this:
protocol _String { func asString() -> String }
extension String : _String { func asString -> String { return self } }
close enough?
- Dave Sweeris
···
On Apr 14, 2016, at 4:31 PM, Brent Royal-Gordon via swift-users <swift-users@swift.org> wrote:
It appears that you can’t extend a generic class/struct with a requirement that a type parameter inherit from a non-protocol:
extension Dictionary where Key : String { … }
The above produces the error “Type ‘Key’ constrained to non-protocol type ‘String’”.
You can't do `Key: String` because `String`, as a struct, cannot have any subtypes. `Key: NSString`, for instance, works.
What you really want to do is say `Key == String`, but this isn't supported right now. (My understanding is that this is basically just an implementation shortcut they took.)
One workaround is to define your own protocol and constrain to that:
protocol _StringType: Hashable {
// Include the String APIs you need to use here.
}
extension String: _StringType {}
extension Dictionary where Key: _StringType { … }
You'll be delighted to know, if you didn't already, that as of Swift 5.1(or earlier), you can do Element == String as you want. Here's an example:
extension Array where Element == String {
/// Filters array, returning items that are prefixed by any item in the query
func filter(withAnyPrefix prefixes: [String]) -> Array<Element> {
return self.filter { (e: String) -> Bool in
e.hasAnyPrefix(prefixes)
}
}
}