extension Array {
func removeObject<T where T : Equatable>(object: T) {
var index = find(self, object)
self.removeAtIndex(index)
}
}
Jednak pojawia się błąd var index = find(self, object)
„T” nie można zamienić na „T”
Próbowałem też z tym podpisem metody: func removeObject(object: AnyObject)
jednak pojawia się ten sam błąd:
„AnyObject” nie jest zamienialne na „T”
Jaki jest właściwy sposób, aby to zrobić?
T where
z deklaracji metody. Więc po prostufunc removeObject<T: Equatable>
. To pytanie jest powiązane: stackoverflow.com/questions/24091046/…Odpowiedzi:
Od wersji Swift 2 można to osiągnąć za pomocą metody rozszerzania protokołu .
removeObject()
jest definiowana jako metoda na wszystkich typach zgodnaRangeReplaceableCollectionType
(w szczególności zArray
), jeśli elementy kolekcji toEquatable
:Przykład:
Aktualizacja dla Swift 2 / Xcode 7 beta 2: Jak zauważyliśmy w komentarzach Airspeed Velocity, obecnie w rzeczywistości możliwe jest napisanie metody na typie ogólnym, który jest bardziej restrykcyjny w szablonie, więc metodę można teraz zdefiniować jako rozszerzenie z
Array
:Rozszerzenie protokołu nadal ma tę zaletę, że można je zastosować do większego zestawu typów.
Aktualizacja dla Swift 3:
źródło
remove(object: Element)
, aby zachować zgodność z wytycznymi projektowymi Swift API i uniknąć gadatliwości. Przesłałem zmianę, która to odzwierciedla.Nie można napisać metody w typie ogólnym, który jest bardziej restrykcyjny w szablonie.
UWAGA : od wersji Swift 2.0 możesz teraz pisać metody, które są bardziej restrykcyjne w szablonie. Jeśli zaktualizowałeś swój kod do wersji 2.0, zapoznaj się z innymi odpowiedziami poniżej, aby poznać nowe opcje implementacji tego za pomocą rozszerzeń.
Powodem, dla którego otrzymujesz błąd,
'T' is not convertible to 'T'
jest to, że w rzeczywistości definiujesz nowe T w swojej metodzie, które nie jest w ogóle związane z oryginalnym T. Jeśli chcesz użyć T w swojej metodzie, możesz to zrobić bez określania go w swojej metodzie.Powodem drugiego błędu
'AnyObject' is not convertible to 'T'
jest to, że nie wszystkie możliwe wartości T są klasami. Aby instancja została przekonwertowana na AnyObject, musi być klasą (nie może to być struktura, wyliczenie itp.).Najlepszym rozwiązaniem jest uczynienie z niej funkcji akceptującej tablicę jako argument:
Zamiast modyfikować oryginalną tablicę, możesz uczynić swoją metodę bardziej bezpieczną dla wątków i wielokrotnego użytku, zwracając kopię:
Alternatywą, której nie polecam, może być cicha awaria metody, jeśli typ przechowywany w tablicy nie może zostać przekonwertowany na szablon metod (jest to równoważne). (Dla jasności używam U zamiast T jako szablonu metody):
Edytuj Aby przezwyciężyć cichą porażkę, możesz zwrócić sukces jako wartość logiczną:
źródło
find
metody?Equatable
protokół. UIView robi tak, tak, będzie działać z UIViewsenumerate(self)
trzeba naprawićself.enumerate()
krótko i zwięźle:
źródło
inout
. Myślę, że nawet zinout
nienaruszonymarray = array.filter() { $0 != object }
przydałoby się.Po przeczytaniu powyższego uważam, że najlepszą odpowiedzią jest:
Próba:
Rozszerzenie tablicy Swift 2 (xcode 7b4):
Próba:
Aktualizacja Swift 3.1
Wróciłem do tego teraz, gdy Swift 3.1 wyszedł. Poniżej znajduje się rozszerzenie, które zapewnia wyczerpujące, szybkie, mutujące i tworzenie wariantów.
Próbki:
źródło
filter
funkcja już obsługuje tę funkcjonalność za Ciebie. Wydaje się, że powiela to funkcjonalność. Ale mimo wszystko dobra odpowiedź:]Dzięki rozszerzeniom protokołu możesz to zrobić,
Ta sama funkcjonalność dla zajęć,
Szybki 2
Szybki 3
Ale jeśli klasa implementuje Equatable, staje się niejednoznaczna, a kompilator zgłasza błąd.
źródło
Binary operator '===' cannot be applied to two elements of type '_' and 'Element'
Korzystając z rozszerzeń protokołów w Swift 2.0
źródło
co powiesz na użycie filtrowania? poniższe działa całkiem dobrze nawet z [AnyObject].
źródło
Istnieje inna możliwość usunięcia elementu z tablicy bez możliwego niebezpiecznego użycia, ponieważ ogólny typ obiektu do usunięcia nie może być taki sam jak typ tablicy. Korzystanie z opcji nie jest również idealnym sposobem, ponieważ są one bardzo wolne. Można więc użyć zamknięcia, które jest już używane na przykład podczas sortowania tablicy.
Gdy rozszerzasz
Array
klasę za pomocą tej funkcji, możesz usunąć elementy, wykonując następujące czynności:Jednak możesz nawet usunąć element tylko wtedy, gdy ma ten sam adres pamięci (
AnyObject
oczywiście tylko dla klas zgodnych z protokołem):Dobrą rzeczą jest to, że możesz określić parametr do porównania. Na przykład, gdy masz tablicę tablic, możesz określić zamknięcie równości jako,
{ $0.count == $1.count }
a pierwsza tablica o tym samym rozmiarze, co tablica do usunięcia, zostanie usunięta z tablicy.Możesz nawet skrócić wywołanie funkcji
mutating func removeFirst(equality: (Element) -> Bool) -> Bool
, używając funkcji as , a następnie zamienić ocenę if naequality(item)
i wywołać funkcjęarray.removeFirst({ $0 == "Banana" })
na przykład.źródło
==
jest to funkcja, możesz ją również nazwać w ten sposób dla dowolnego typu implementującego==
(takiego jak String, Int itp.):array.removeFirst("Banana", equality:==)
Nie ma potrzeby przedłużania:
źródło
Używanie
indexOf
zamiastfor
lubenumerate
:źródło
Może nie zrozumiałem pytania.
Dlaczego to nie zadziała?
źródło
W końcu skończyłem z następującym kodem.
źródło
Udało mi się usunąć
[String:AnyObject]
z tablicy[[String:AnyObject]]
, implementując liczbę poza pętlą for do reprezentowania indeksu od.find
i.filter
nie są zgodne z[String:AnyObject]
.źródło
Wdrożenie w Swift 2:
źródło
Udało mi się to zrobić z:
źródło
if(index)
jest nieważne