Uważam to za bardziej zabawne niż cokolwiek innego. Naprawiłem to, ale zastanawiam się nad przyczyną. Tutaj jest błąd: DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
. Dlaczego narzeka? Wydaje się, że jest to jedno z najprostszych możliwych wyrażeń.
Kompilator wskazuje na columns + ");";
sekcję
func tableName() -> String { return("users"); }
func createTableStatement(schema: [String]) -> String {
var schema = schema;
schema.append("id string");
schema.append("created integer");
schema.append("updated integer");
schema.append("model blob");
var columns: String = ",".join(schema);
var statement = "create table if not exists " + self.tableName() + "(" + columns + ");";
return(statement);
}
poprawka to:
var statement = "create table if not exists " + self.tableName();
statement += "(" + columns + ");";
to również działa (przez @efischency), ale nie podoba mi się to tak bardzo, ponieważ myślę, że (
się zgubisz:
var statement = "create table if not exists \(self.tableName()) (\(columns))"
ios
xcode
swift
compiler-errors
functional-programming
Kendrick Taylor
źródło
źródło
var statement = "create table if not exists \(self.tableName()) (\(columns))"
:?+
.Odpowiedzi:
Nie jestem ekspertem od kompilatorów - nie wiem, czy ta odpowiedź „zmieni Twój sposób myślenia w znaczący sposób”, ale moje zrozumienie problemu jest następujące:
Ma to związek z wnioskiem o typie. Za każdym razem, gdy używasz
+
operatora, Swift musi przeszukać wszystkie możliwe przeciążenia+
i wywnioskować, której wersji+
używasz. Naliczyłem dla+
operatora nieco poniżej 30 przeciążeń . To wiele możliwości, a kiedy łączysz razem 4 lub 5+
operacji i prosisz kompilator o wywnioskowanie wszystkich argumentów, żądasz znacznie więcej, niż mogłoby się wydawać na pierwszy rzut oka.To wnioskowanie może się skomplikować - na przykład, jeśli dodasz a
UInt8
iInt
using+
, wynikiem będzie anInt
, ale jest pewna praca, która wymaga oceny reguł mieszania typów z operatorami.A kiedy używasz literałów, takich jak
String
literały w twoim przykładzie, kompilator wykonuje pracę polegającą na konwersjiString
literału na aString
, a następnie wykonuje pracę polegającą na wywnioskowaniu argumentu i zwracaniu typów dla+
operatora itp.Jeśli wyrażenie jest wystarczająco złożone - tj. Wymaga od kompilatora wyciągnięcia zbyt wielu wniosków na temat argumentów i operatorów - kończy pracę i informuje, że zakończyło pracę.
Zamknięcie kompilatora, gdy wyrażenie osiągnie pewien poziom złożoności, jest zamierzone. Alternatywą jest pozwolić kompilatorowi spróbować to zrobić i sprawdzić, czy może, ale jest to ryzykowne - kompilator może próbować bez końca, grzęznąć lub po prostu się zawiesić. Rozumiem więc, że istnieje statyczny próg złożoności wyrażenia, którego kompilator nie wykroczy.
Rozumiem, że zespół Swift pracuje nad optymalizacjami kompilatora, które sprawią, że te błędy będą mniej powszechne. Możesz dowiedzieć się o tym trochę na forach Apple Developer, klikając to łącze .
Na forach deweloperów Chris Lattner poprosił ludzi o zgłaszanie tych błędów jako raportów radarowych, ponieważ aktywnie pracują nad ich naprawieniem.
Tak to rozumiem po przeczytaniu kilku postów tutaj i na forum deweloperów na ten temat, ale moje rozumienie kompilatorów jest naiwne i mam nadzieję, że ktoś z głębszą wiedzą o tym, jak radzi sobie z tymi zadaniami, rozwinie to, co ja napisałem tutaj.
źródło
Jest to prawie taka sama jak zaakceptowana odpowiedź, ale z dodatkowymi dialogami (miałem z Robem Napierem, jego innymi odpowiedziami oraz Mattem, Oliverem, Davidem ze Slacka) i linkami.
Zobacz komentarze w tej dyskusji. Istota tego jest taka:
+
jest mocno przeciążony (wydaje się, że Apple naprawił to w niektórych przypadkach)+
Operator jest mocno przeciążony, ponieważ od teraz ma 27 różnych funkcji, więc jeśli złączenie 4 strings czyli masz 3+
operatorów kompilator musi się sprawdzić między 27 operatorów za każdym razem, więc to 27 ^ 3 razy. Ale to nie wszystko.Istnieje również sprawdzić , czy
lhs
irhs
z+
funkcjami są zarówno ważne, jeżeli są one wywołuje aż do jądrzeappend
nazywa. Jak widać , może dojść do szeregu dość intensywnych kontroli . Jeśli ciąg jest przechowywany w sposób nieciągły, co wydaje się mieć miejsce, jeśli ciąg, z którym masz do czynienia, jest faktycznie mostkowany do NSString. Swift musi następnie ponownie złożyć wszystkie bufory tablicy bajtów w jeden ciągły bufor, co wymaga tworzenia nowych buforów po drodze. a potem w końcu otrzymujesz jeden bufor, który zawiera ciąg, który próbujesz połączyć.Krótko mówiąc, istnieją 3 klastry kontroli kompilatora, które spowalniają Cię, tj. Każde wyrażenie podrzędne musi zostać ponownie przemyślane w świetle wszystkiego, co może zwrócić . W rezultacie łączenie ciągów za pomocą interpolacji, tj. Używanie
" My fullName is \(firstName) \(LastName)"
jest znacznie lepsze niż"My firstName is" + firstName + LastName
ponieważ interpolacja nie ma żadnego przeciążeniaSwift 3 wprowadził pewne ulepszenia. Aby uzyskać więcej informacji, przeczytaj artykuł Jak scalić wiele tablic bez spowalniania kompilatora? . Niemniej jednak
+
operator jest nadal przeciążony i lepiej jest używać interpolacji ciągów dla dłuższych ciągówWykorzystanie opcji (bieżący problem - dostępne rozwiązanie)
W tym bardzo prostym projekcie:
Czas kompilacji funkcji jest następujący:
Zwróć uwagę, jak szalony jest czas trwania kompilacji
concatenatedOptionals
.Można to rozwiązać, wykonując:
który się kompiluje
88ms
Główną przyczyną problemu jest to, że kompilator nie identyfikuje
""
pliku jakoString
. Właściwie toExpressibleByStringLiteral
Kompilator zobaczy
??
i będzie musiał przeglądać wszystkie typy, które są zgodne z tym protokołem , aż znajdzie typ, który może być domyślnyString
. UżywającemptyString
które jest zakodowane na stałeString
, kompilator nie musi już przechodzić przez wszystkie zgodne typyExpressibleByStringLiteral
Aby dowiedzieć się, jak rejestrować czasy kompilacji, zobacz tutaj lub tutaj
Inne podobne odpowiedzi Roba Napiera na SO:
Dlaczego tworzenie dodawania ciągów trwa tak długo?
Jak połączyć wiele tablic bez spowalniania kompilatora?
Swift Array zawiera funkcję, która wydłuża czas kompilacji
źródło
Bez względu na to, co mówisz, jest to dość śmieszne! :)
Ale to łatwo przechodzi
źródło
Miałem podobny problem:
W Xcode 9.3 linia wygląda tak:
Po zmianie na coś takiego:
wszystko się udało.
Prawdopodobnie ma to coś wspólnego z kompilatorem Swift, który próbuje wywnioskować typ danych z otaczającego go kodu.
źródło