[英]Extending a Collection where the Element type is generic (Swift)
It's simple to extend a Collection type in swift to have a custom function for particular Element types: 在swift中扩展Collection类型以使特定Element类型具有自定义函数很简单:
struct MyStruct {
let string: String
}
extension Set where Element == MyStruct {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
But suppose your Element type is generic? 但是假设您的Element类型是通用的?
protocol MyProtocol {}
struct MyGenericStruct<T: MyProtocol> {
let string: String
}
// error on next line:
// error: expected '>' to complete generic argument list
// extension Set where Element == MyGenericStruct<T: MyProtocol> {
// ^
extension Set where Element == MyGenericStruct<T: MyProtocol> {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
// error on next line:
// error: use of undeclared type 'T'
// extension Set where Element == MyGenericStruct<T> {
// ^
extension Set where Element == MyGenericStruct<T> {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
It's unclear to me how to declare that my element is a generic. 我不清楚如何声明我的元素是通用的。
If I do understand the purpose, you probably need to have more implementation in your protocol
and structure
. 如果我确实理解了目的,您可能需要在
protocol
和structure
实现更多实现。
First, element's protocol has to be hashable and equitable. 首先,元素的协议必须是可混合和公平的。
protocol MyProtocol: Hashable, Equatable {
var string: String { get }
}
Therefore, MyGenericStruct
will look like the following. 因此,
MyGenericStruct
将如下所示。
struct MyGenericStruct: MyProtocol {
let string: String
var hashValue: Int {
get {
return string.hashValue
}
}
static func ==(lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
Then, declare extension with constraints specified by a where clause for MyProtocol
然后,使用
MyProtocol
的where子句指定的约束声明扩展
extension Set where Element: MyProtocol {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
Finally, let's do a test and see its result. 最后,让我们做一个测试,看看它的结果。
// Example
let set: Set = [
MyGenericStruct(string: "Watermelon"),
MyGenericStruct(string: "Orange"),
MyGenericStruct(string: "Banana")
]
let output = set.getFirstWith(string: "Orange")
print(output)
In my playground with Xcode 8, I can get Optional(MyGenericStruct(string: "Orange"))
in log. 在我的Xcode 8操场上,我可以在日志中获得
Optional(MyGenericStruct(string: "Orange"))
。
[UPDATED1]
To make an Extension
on Set<MyGenericStruct>
only: [UPDATED1]
仅在Set<MyGenericStruct>
上进行Extension
:
extension Set where Element == MyGenericStruct {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
[UPDATED2]
In case to keep MyGenericStruct<T: MyProtocol>
declaration as stated is necessary, another approach to implement Set
extension: [UPDATED2]
如果要保持MyGenericStruct<T: MyProtocol>
声明是必要的,另一种实现Set
扩展的方法:
protocol MyProtocol {
}
struct BaseStruct1: MyProtocol {
}
struct BaseStruct2: MyProtocol {
}
protocol ContainStringProtocol: Hashable {
var string: String { get }
}
struct MyGenericStruct<T: MyProtocol>: ContainStringProtocol {
var string: String
var hashValue: Int {
get {
return string.hashValue
}
}
init(string: String) {
self.string = string
}
static func ==(lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
extension Set where Element: ContainStringProtocol {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
// Example
let set1: Set = [
MyGenericStruct<BaseStruct1>(string: "Watermelon"),
MyGenericStruct<BaseStruct1>(string: "Orange"),
MyGenericStruct<BaseStruct1>(string: "Banana")
]
let output1 = set1.getFirstWith(string: "Orange")
print(output1!)
let set2: Set = [
MyGenericStruct<BaseStruct2>(string: "Watermelon"),
MyGenericStruct<BaseStruct2>(string: "Orange"),
MyGenericStruct<BaseStruct2>(string: "Banana")
]
let output2 = set2.getFirstWith(string: "Orange")
print(output2!)
Swift 3.1, xCode 8.3.3 Swift 3.1,xCode 8.3.3
import Foundation
struct MyStruct:Hashable {
let string: String
static func == (lhs: MyStruct, rhs: MyStruct) -> Bool {
return lhs.string == rhs.string
}
var hashValue: Int {
return string.hash
}
}
extension Set where Element == MyStruct {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
var set = Set<MyStruct>()
set.insert(MyStruct(string: "123"))
set.insert(MyStruct(string: "231"))
print(String(describing:set.getFirstWith(string: "123")))
print(String(describing:set.getFirstWith(string: "231")))
///////////////////////////////////
protocol MyProtocol {}
struct MyType1: MyProtocol {}
struct MyType2: MyProtocol {}
struct MyGenericStruct<T: MyProtocol>: Hashable {
let string: String
static func == (lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.string == rhs.string
}
var hashValue: Int {
return string.hash
}
}
extension Set where Element == AnyHashable {
func getFirstWith(string: String) -> Element? {
return filter{ element -> Bool in
if let _element = element as? MyGenericStruct<MyType1> {
if _element.string == string {
return true
}
}
if let _element = element as? MyGenericStruct<MyType2> {
if _element.string == string {
return true
}
}
return false
}.first
}
}
var set2 = Set<AnyHashable>()
set2.insert(MyGenericStruct<MyType1>(string: "abc"))
set2.insert(MyGenericStruct<MyType2>(string: "cba"))
print(String(describing: set2.getFirstWith(string: "abc")))
print(String(describing:set2.getFirstWith(string: "cba")))
Answering my own question here on request. 根据要求在这里回答我自己的问题。
I was unable to figure out how to make this an extension on Set
. 我无法弄清楚如何将它作为
Set
的扩展。
Instead, we wrote a little utility function. 相反,我们写了一个小实用函数。 Not as clear as a extension, but gets the work done.
不像扩展那样清晰,但完成工作。 It looks like this:
它看起来像这样:
func getFirst<T: MyProtocol>(fromSet set: Set<MyGenericStruct<T>>, whereStringIs string: String) -> MyGenericStruct<T>? {
return set.first(where: { $0.string == string })
}
As others have noted, MyGenericStruct
needs to be Hashable. 正如其他人所说,
MyGenericStruct
需要是Hashable。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.