2015-04-18 33 views
6

Podczas gdy find(["a", "b"], "c") działa bez problemów, pojawia się błąd podczas próby znalezienia indeksu struktury wewnątrz tablica struktur:Swift Nie można wywołać 'find' z listą argumentów typu '([Score], Score)' gdzie Score jest strukturą

struct Score 
{ 
    //... 
} 

var scores: [Score] = //... 
var score: Score = //... 

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

Chociaż może to być problem ze strukturami, które nie mogą być domyślnie porównywane ze sobą. Ale zmiana definicji Score na class daje mi ten sam błąd.

+0

Znaleźliście już przyczynę. 'Score' musi implementować protokół' Equatable' (bez względu na to, czy jest to struktura czy klasa). –

+1

Prawdopodobnie ten sam problem, co tutaj: http://stackoverflow.com/questions/27887387/how-to-use-contains-withtwoys-grows-of-objects –

Odpowiedz

14

EDYCJA: od Swift 2.0, jest teraz wbudowana wersja find, która ma zamknięcie, więc nie musisz pisać własnego - ale również zmieniono nazwę find na indexOf i jest teraz rozszerzeniem protokołu CollectionType, więc nazywasz to jak metoda:

// 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 sprzed 2,0 odpowiedź poniżej


Podczas odpowiedzi sugeruje, co klasa Equatable może działać dobrze, polecam trochę ostrożności przed wyborem, aby to zrobić. Powodem jest to, że, jak stwierdzają doktorzy, równość wymaga substytucyjności, a operator musi być refleksyjny, symetryczny i przechodni. Jeśli tego nie zrobisz, możesz uzyskać bardzo dziwne zachowanie podczas korzystania z algorytmów takich jak equals, sort itd. Zachowaj szczególną ostrożność, jeśli implementujesz Equatable na niefinałowych zajęciach. Jeśli jesteś pewien, że możesz spełnić wymagania, przejdź do niego i zadziała find.

Jeśli nie, to alternatywą można rozważyć pisze funkcję powinien się w bibliotece standardowej, ale nie jest to, co jest find że bierze Zamknięcie:

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 
} 

Gdy masz możesz podać dowolne pasujące kryteria. Na przykład, jeśli obiekty są klasami, można użyć równości odniesienia:

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

Wygląda na to, że zmienna 'indexOf' została zmieniona na' index (of:) 'w Swift 3. – Pang

7

interfejs dla funkcji find jest/było:

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

Ten mówi, że CollectionType z C musi mieć elementy, które są Equatable, a ponadto, że value należy również Equatable.

[Uwaga Swift 3.0: od wersji Swift 3.0 trzeba użyć funkcji index, która występuje w dwóch wersjach. W pierwszym, będziemy dostarczać swoje własne orzeczenie:

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

w drugim, Twoje elementy muszą być equatable:

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

Jeśli zdecydujesz się pójść drogą equatable, wówczas stosuje się następujące . Uwaga Koniec]

Twój Score struct nie jest Equatable i stąd błąd. Musisz dowiedzieć się, co to znaczy, że wyniki są sobie równe. Może to jakiś numeryczny "wynik"; może to jest "wynik" i "identyfikator użytkownika". To zależy od abstrakcji Score. Gdy wiesz, wdrożyć == używając:

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

Uwaga: jeśli używasz class a więc wyniki mają „tożsamość”, a następnie można zaimplementować to jako:

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

Twój przykład z ciągów działa, ponieważ String to Equatable. Jeśli spojrzeć na kod SWIFT biblioteki zobaczysz:

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

Jak mówili inni, obiekty, które wyszukujące muszą być zgodne z Equatable protokołu.

Więc trzeba dodać rozszerzenie do swojego wyniku struktury, która informuje kompilator, że jest on zgodny z tym protokołem:

extension Score: Equatable {} 

A potem trzeba zaimplementować funkcję == dla tej klasy:

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

Dlaczego pojawia się ten sam błąd podczas wykonywania 'Score' zamiast tego "klasa"? Czy "==" nie dotyczy klas? – Rivera

+0

Nr == nie jest poprawny dla żadnego niestandardowego obiektu, chyba że zdefiniujesz go jako opisany w mojej odpowiedzi. –