To pytanie ma tę samą formę, co kopia i to samo rozwiązanie. Uczyń mutację raczej inicjatorem niż metodą.
protocol Copyable {
init(copy: Self)
}
protocol Mutatable : Copyable {
init(byMutating: Self)
}
class C : Mutatable {
var a = 0
required init(_ a: Int) {
self.a = a
}
required init(copy: C) {
a = copy.a
}
required convenience init(byMutating: C) {
self.init(copy: byMutating)
self.a++
}
}
// These are purely for convenience
func copy<T : Copyable>(x: T) -> T {
return x.dynamicType(copy: x)
}
func mutated<T: Mutatable>(x: T) -> T {
return x.dynamicType(byMutating: x)
}
Ale powtórzyć punkt Mattt w powiązanym artykule, można mieć składnię C(copy: x)
dość wygodnie, i można mieć składnię copy(x)
całkiem wygodnie, i zawsze jest x.dynamicType(copy: x)
. Ale nie można mieć składni x.copy()
bez irytującej pracy. Musisz albo duplikować func copy() -> Self { return copy(self) }
w każdej klasie, albo musisz stworzyć jakąś konkretną klasę, która implementuje tę metodę i ostatecznie dziedziczy C
. Jest to obecnie podstawowe ograniczenie Swift. Zgadzam się z diagnozą możliwych rozwiązań przez Mattta i podejrzewam, że jakiś system cech, prawdopodobnie według Scali, prawdopodobnie zostanie dodany w przyszłości.
Warto się skupić na komentarzu Mattta, że "wszystko to podkreśla znaczące napięcie między metodami i funkcjami w Swift". Jest to kolejny sposób powiedzenia, że istnieją napięcia między paradygmatem obiektowym a paradygmatem funkcjonalnym, a poruszanie się między nimi może powodować pewne rozłączenia. Języki starają się opisywać ten problem różnymi funkcjami, ale istnieją istotne różnice między obiektami z wiadomościami i właściwościami, a funkcjami z danymi i kombinatorami, a "uzyskiwanie najlepszych z obu światów" może czasami powodować pewne ostre krawędzie.
Łatwo jest zapomnieć, porównując Swift z innymi językami, że istnieje duża różnica między wersjami 0.9 i 2.2. Wiele rzeczy, które przyjmujemy za pewnik w naszych ulubionych językach, również nie istniało w ich wersjach v1.
Do Twojego komentarza, można myśleć, że mutated
jest typu Self
. Ale jest to typ C
, jak wskazuje autouzupełnianie. Tak jak poprzednio, C
to nie to samo co Self
, chyba że możesz obiecać, że nie ma podklas (C
jest albo final
lub struct). Typy Swift są rozwiązywane podczas kompilacji, a nie w czasie wykonywania, chyba że używasz dynamicType
.
być trochę bardziej szczegółowe, Swift patrzy na tej linii:
let mutated = copy(self)
Zauważa, że copy
jest rodzajowy od typu jej parametr i musi skonstruować wersję copy
w czasie kompilacji, aby zadzwonić. Nie ma typu Self
. To tylko symbol zastępczy i musi zostać rozwiązany podczas kompilacji. Typ self
w tym zakresie leksykalnym to C
. Więc konstruuje copy<C>
. Ale jeśli podklasowałeś C
, może to być zła funkcja (w tym przypadku byłaby). Jest to bardzo blisko związane z: https://stackoverflow.com/a/25549841/97337.
Fakt, że autouzupełnianie typu mówi: (C)
, a nie C
, jest niewielkim efektem ubocznym funkcjonowania i funkcjonalności Swift i pojawia się dość regularnie, ale jeszcze nie spotkałem się z przypadkiem, w którym to naprawdę miało znaczenie. Funkcja Swift, taka jak func f(x: Int, y:Int)
, nie ma w rzeczywistości dwóch parametrów. Ma jeden parametr 2-towy typu (Int, Int)
. Fakt ten jest ważny dla funkcjonowania składni curry (zobacz Swift Programming Language, aby dowiedzieć się więcej o curry w Swift). Więc kiedy specjalizujesz się w copy
, wyspecjalizowałeś ją w 1-kodzie typu (C)
. (Możliwe, że kompilator próbuje to zrobić jako jedną z wielu prób, i to jest właśnie ta, o której donosi.) W Swift każda wartość może zostać zmiennie wymieniana na 1-tkę tego samego typu. Tak więc zwrot copy
jest tak naprawdę 1-krotną wersją C
, napisaną (C)
. Podejrzewam, że kompilator Swift poprawi swoje wiadomości z czasem, aby usunąć obce nawiasy, ale dlatego czasami się pojawiają.
Ok, więc używaj inicjalizatorów do wszystkiego. Rozumiem. Dzięki jeszcze raz! – aeubanks
Moje pytanie brzmi: dlaczego oryginalny kod nie działa, jeśli 'copy (T) -> T' zwraca klasę, która go nazwała? W funkcji 'mutated()' powinien zwracać 'Self' w prawo? Nawet jeśli jest lepszy sposób na zrobienie tego, nadal jestem ciekawy, jak działa Swift. – aeubanks
zaktualizowano o więcej informacji –