Swift Cannot call 'find' with a list argument of type '([Score], Score)', where Score is a structure

While find(["a", "b"], "c") works without problems, I get an error when I try to find the index of the structure inside the array of structures:

 struct Score { //... } var scores: [Score] = //... var score: Score = //... find(self.scores, score) // Error: Cannot invoke 'find' with an argument list of type '([Score], Score)' 

I though it can be a problem with structures which by default cannot be compared with each other. But changing the Score definition to class gives me the same error.

+6
source share
3 answers

EDIT: with Swift 2.0 there is now a built-in version of find that takes closure, so you don’t have to write your own, but also find was renamed indexOf and is now an extension of the CollectionType protocol, so you name it as a method:

 // if you make `Score` conform to `Equatable: if let idx = self.scores.indexOf(score) { } // or if you don't make it Equatable, you can just use a closure: // (see original answer below for why you might prefer to do this) if let idx = scores.indexOf({$0.scoreval == 3}) { } 

Original answer before 2.0 after


While the answers suggesting making your Equatable class might work nicely, I would recommend a little caution before choosing this. The reason is because, as docs claims, equatability implies substitutability, and your == operator must be reflective, symmetric, and transitive. If you do not adhere to this, you may encounter very strange behavior when using algorithms such as equals , sort , etc. Be especially careful when implementing Equatable in non-final classes. If you are sure that you can satisfy the requirements, go for it and find will work.

If not, an alternative that you might consider is to write a function that should be in the standard library, but not there, which is find , which takes a closure:

 func find<C: CollectionType>(source: C, match: C.Generator.Element -> Bool) -> C.Index { for idx in indices(source) { if match(source[idx]) { return idx } } return nil } 

After that, you can provide any suitable criteria that you prefer. For example, if your objects are classes, you can use referential equality:

 let idx = find(scores) { $0 === $1 } 
+14
source

The interface for the find function is / was:

 func find<C : CollectionType where C.Generator.Element : Equatable>(domain: C, value: C.Generator.Element) -> C.Index? 

This suggests that CollectionType of C should contain Equatable elements and, in addition, value should also be Equatable .

[ Swift 3.0 Note : With Swift 3.0 you will need to use the index function, which comes in two flavors. First, you provide your own predicate:

 func index(where: (Self.Generator.Element) -> Bool) -> Self.Index? 

In the second case, your elements should be equivalent:

 // Where Generator.Element : Equatable func index(of: Self.Generator.Element) -> Self.Index? 

If you decide to switch to the Equatable route, the following applies. Note> ]

The structure of the Score not Equatable and therefore an error. You need to figure out what it means that the points must be equal to each other. Perhaps this is a somewhat numerical estimate; perhaps this is a "rating" and "user ID". It depends on your abstraction. Score . Once you know, you implement == using:

 func == (lhs:Score, rhs:Score) -> Bool { return // condition for what it means to be equal } 

Note: if you use class and therefore points have an "identifier", you can implement this as:

 func == (lhs:Score, rhs:Score) -> Bool { return lhs === rhs } 

Your string example works because String is Equatable . If you look in the code of the Swift library, you will see:

 extension String : Equatable {} func ==(lhs: String, rhs: String) -> Bool 
+7
source

As others have said, the objects you are looking for must conform to the Equatable protocol.

So, you need to add an extension to your Score structure, which tells the compiler that it conforms to this protocol:

 extension Score: Equatable {} 

And then you need to implement the == function for this class:

 public func ==(lhs: Score, rhs: Score) -> Bool { return lhs.whatever == rhs.whatever //replace with code for your struct. } 
+1
source

Source: https://habr.com/ru/post/985421/


All Articles