2014-09-02 10 views
5
func getIndex<T: Equatable>(valueToFind: T) -> Int? {...} 

mutating func replaceObjectWithObject<T: Equatable>(obj1: T, obj2: T) { 
    if let index = self.getIndex(obj1) { 
     self.removeAtIndex(index) 
     self.insert(obj2, atIndex: index)   // Error here: 'T' is not convertible to 'T' 
    } 
} 

Mam tę funkcję, która ma zastąpić element innym elementem. Ale nie jestem bardzo zaznajomiony z Generics i nie wiem, dlaczego to nie działa. Proszę pomóż.Swift Array.insert generics

jeśli usunąć Equatable od mutacji func komunikat o błędzie skacze do pierwszej linii w tej func i gdybym wówczas zastąpi że z func find() który daje mi ten sam błąd, jak na linii 3.

+0

można zapewnić realizację 'metody insert', lub przynajmniej jego podpis? – Antonio

+0

nvm ... Rozumiem to - to rozszerzenie 'Array', prawda? – Antonio

+0

Nieco styczny, ale ten komunikat o błędzie jest mylący, ponieważ 'Tablica' używa T jako swojego ogólnego podtypu.Mówi się, że 'T' (typ ogólny dla tej funkcji) nie jest konwertowalny na' T' (typ ogólny dla tablicy). Jeśli zmienisz podpis metody na "U" zamiast "T", będzie to bardziej przejrzyste. –

Odpowiedz

0

Jak czy zadeklarowałeś swoje rozszerzenie Array? Problem polega na tym, że funkcje ogólne wymagają argumentów typu Equatable, ale po zadeklarowaniu tablicy określono konkretną implementację klasy Equatable, na przykład String. A T nie jest String bez obsady.

4

To nie jest faktycznie możliwe poprzez rozszerzenie ramach istniejącego systemu protokołów i generycznych w Swift - nie można dodać dodatkowe ograniczenia w rodzajowym podtyp typu, więc nie można rozszerzyć Array z metodą wymaga to, aby jego zawartość była zgodna z Equatable.

Widać to ograniczenie w działaniu z wbudowanym typu Array - nie ma myArray.find(element) metoda, ale nie jest globalna funkcja find() że trwa zbieranie i element, z ogólnym ograniczeniem, że elementy kolekcji za są Equatable:

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

ty może zrobić to za metoda - wystarczy napisać podobną funkcję najwyższego poziomu:

func replaceObjectWithObject<C : RangeReplaceableCollectionType where C.Generator.Element : Equatable>(inout collection: C, obj1: C.Generator.Element, obj2: C.Generator.Element) { 
    if let index = find(collection, obj1) { 
     removeAtIndex(&collection, index) 
     insert(&collection, obj2, atIndex: index) 
    } 
} 

var myArray = [1, 2, 3, 4, 5] 
replaceObjectWithObject(&myArray, 2, 7) 
// 1, 2, 7, 4, 5 
+0

Użycie niezadeklarowanego typu RangeReplaceableCollectionType, "Generator" nie jest członkiem typu "C" – Arbitur

+0

Którą wersję beta używasz? 'RangeReplaceableCollectionType' pojawił się w wersji beta 6. –

+0

Hehe ... Używam wersji beta 4 – Arbitur

0

To, co próbujesz zrobić, nie może zostać wykonane przy użyciu funkcji klasy/struktury - @Nate Cook dostarczył bardzo dobre rozwiązanie przy użyciu funkcji globalnej.

Nawiasem mówiąc, przyczyna, dla której nie działa, staje się bardziej przejrzysta, jeśli w metodach rozszerzeń zastąpiono T przez V: są to różne typy. To wyjaśnia również, dlaczego ten sam błąd występuje, jeśli usuniesz zależność od Equatable: tablica zawiera obiekty typu T, ale próbujesz wstawić wartość V.

0

Ta odpowiedź jest duplikatem pytanie zaznaczono ją: Create swift array extension for typed arrays

Jest na to sposób, aby rozwiązać rozszerzenia Array, które mają zastosowanie tylko do określonego rodzaju tablicy. Ale musisz użyć tablicy z elementami typu Any, który omija system typu Swift. Ale kod nadal działa, nawet jeśli w tablicy znajdują się elementy innych typów. Zobacz przykład poniżej.

class Job { 
    var name: String 
    var id: Int 
    var completed: Bool 

    init(name: String, id: Int, completed: Bool) { 
     self.name = name 
     self.id = id 
     self.completed = completed 
    } 
} 

var jobs: [Any] = [ 
    Job(name: "Carpenter", id: 32, completed: true), 
    Job(name: "Engineer", id: 123, completed: false), 
    Job(name: "Pilot", id: 332, completed: true)] 



extension Array { 

    // These methods are intended for arrays that contain instances of Job 

    func withId(id: Int) -> Job? { 
     for j in self { 
      if (j as? Job)?.id == id { 
       return j as? Job 
      } 
     } 
     return nil 
    } 

    func thatAreCompleted() -> [Job] { 
     let completedJobs = self.filter { ($0 as? Job) != nil && ($0 as? Job)!.completed} 
     return completedJobs.map { $0 as! Job } 
    } 
} 

jobs.withId(332) 
println(jobs.withId(332)?.name) 
//prints "Optional("Pilot")" 

let completedJobs = jobs.thatAreCompleted().map {$0.name} 
println(completedJobs) 
//prints "[Carpenter, Pilot]" 
0

Można używać rozszerzenia z WHERE przymusu i Używam Xcode 7.3.1

extension Array where Element: Equatable { 
    func testEqutability() { 
     let e1 = self[0] 
     let e2 = self[1] 
     if e1 == e2 {//now we can use == to test Element equtability 
      //do something 
     } 
    } 
}