Swift Cannot invoke 'find' with an argument list of type '([Score], Score)' where Score is a struct

狂风中的少年 提交于 2019-12-21 04:50:42

问题


While find(["a", "b"], "c") works with no problems, I get an error when trying to find the index of a structure inside an 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 could be a problem with structures that can't be compared to each other by default. But changing Scores definition to class gives me the same error.


回答1:


EDIT: as of Swift 2.0, there is now a built-in version of find that takes a closure so you don’t have to write your own – but also, find has been renamed indexOf, and is now a protocol extension of CollectionType, so you call it like 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 pre-2.0 answer below


While the answers suggesting making your class Equatable may work nicely, I'd recommend a bit of caution before choosing to do this. The reason being that, as the docs state, equatability implies substitutability, and your == operator must be reflexive, symmetric and transitive. If you don't adhere to this, you might get some very weird behavior when using algorithms like equals, sort etc. Be especially cautious if implementing Equatable on non-final classes. If you're sure you can meet requirements, go for it, and find will work.

If not, an alternative you could consider is writing a function that ought to be in the standard library but isn't, which is a find that 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
}

Once you have this, you can supply any matching criteria you prefer. For example, if your objects are classes you could use reference equality:

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



回答2:


The interface for the function find is/was:

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

This says that the CollectionType of C must have elements that are Equatable and, furthermore, that the value must also be Equatable.

[Note Swift 3.0: As of Swift 3.0, you'll need to use the index function which comes in two variations. In the first, you'll supply your own predicate:

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

In the second, your elements need to be equatable:

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

If you decide to go the equatable route, then the following applies. Note End]

Your Score struct is not Equatable and hence the error. You'll need to figure out what it means for scores to be equal to one another. Maybe it is some numerical 'score'; maybe it is a 'score' and a 'user id'. It depends on your Score abstraction. 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 thus scores have 'identity' then you can implement this as:

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

Your example with strings works because String is Equatable. If you look in the Swift library code you'll see:

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



回答3:


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

So you need to add an extension to your Score struct that tells the compiler that it conforms to that protocol:

extension Score: Equatable {}

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

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


来源:https://stackoverflow.com/questions/29718195/swift-cannot-invoke-find-with-an-argument-list-of-type-score-score-wher

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!