Je trouve cela plus amusant que tout. Je l'ai réparé, mais je m'interroge sur la cause. Voici l'erreur: DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
. Pourquoi se plaint-il? Cela semble être l'une des expressions les plus simples possibles.
Le compilateur pointe vers la columns + ");";
section
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);
}
le correctif est:
var statement = "create table if not exists " + self.tableName();
statement += "(" + columns + ");";
cela fonctionne aussi (via @efischency) mais je ne l'aime pas autant car je pense que ça (
se perd:
var statement = "create table if not exists \(self.tableName()) (\(columns))"
ios
xcode
swift
compiler-errors
functional-programming
Kendrick Taylor
la source
la source
var statement = "create table if not exists \(self.tableName()) (\(columns))"
:?+
.Réponses:
Je ne suis pas un expert des compilateurs - je ne sais pas si cette réponse "changera votre façon de penser de manière significative", mais ma compréhension du problème est la suivante:
Cela a à voir avec l'inférence de type. Chaque fois que vous utilisez l'
+
opérateur, Swift doit rechercher toutes les surcharges possibles+
et en déduire quelle version de+
vous utilisez. J'ai compté un peu moins de 30 surcharges pour l'+
opérateur. C'est beaucoup de possibilités, et quand vous enchaînez 4 ou 5+
opérations ensemble et demandez au compilateur de déduire tous les arguments, vous demandez beaucoup plus qu'il n'y paraît à première vue.Cette inférence peut devenir compliquée - par exemple, si vous ajoutez un
UInt8
et unInt
using+
, la sortie sera unInt
, mais il y a du travail à faire pour évaluer les règles de mélange de types avec des opérateurs.Et lorsque vous utilisez des littéraux, comme les
String
littéraux dans votre exemple, le compilateur effectue le travail de conversion duString
littéral en aString
, puis effectue le travail d'inférence de l'argument et des types de retour pour l'+
opérateur, etc.Si une expression est suffisamment complexe - c'est-à-dire qu'elle oblige le compilateur à faire trop de déductions sur les arguments et les opérateurs - elle se ferme et vous dit qu'elle se ferme.
Faire quitter le compilateur une fois qu'une expression atteint un certain niveau de complexité est intentionnel. L'alternative est de laisser le compilateur essayer de le faire, et voir si c'est possible, mais c'est risqué - le compilateur pourrait continuer à essayer pour toujours, s'enliser ou simplement planter. Donc, je crois comprendre qu'il existe un seuil statique pour la complexité d'une expression que le compilateur n'ira pas au-delà.
Je crois comprendre que l'équipe Swift travaille sur des optimisations du compilateur qui rendront ces erreurs moins courantes. Vous pouvez en apprendre un peu plus à ce sujet sur les forums des développeurs Apple en cliquant sur ce lien .
Sur les forums de développement, Chris Lattner a demandé aux gens de déposer ces erreurs sous forme de rapports radar, car ils travaillent activement à les corriger.
C'est ainsi que je le comprends après avoir lu un certain nombre de messages ici et sur le forum Dev à ce sujet, mais ma compréhension des compilateurs est naïve, et j'espère que quelqu'un avec une connaissance plus approfondie de la façon dont ils gèrent ces tâches développera ce que je ont écrit ici.
la source
C'est presque la même chose que la réponse acceptée mais avec quelques dialogues supplémentaires (j'ai eu avec Rob Napier, ses autres réponses et Matt, Oliver, David de Slack) et des liens.
Voir les commentaires dans cette discussion. L'essentiel est:
+
est fortement surchargé (Apple semble avoir corrigé ce problème dans certains cas)L'
+
opérateur est fortement surchargé, à partir de maintenant il a 27 fonctions différentes, donc si vous concaténez 4 chaînes, c'est-à-dire que vous avez 3+
opérateurs, le compilateur doit vérifier entre 27 opérateurs à chaque fois, soit 27 ^ 3 fois. Mais ce n'est pas ça.Il y a aussi une vérification pour voir si les fonctions
lhs
etrhs
des+
fonctions sont toutes les deux valides si elles sontappend
appelées à cœur de l' appelé. Là, vous pouvez voir qu'il y a un certain nombre de vérifications quelque peu intensives qui peuvent avoir lieu. Si la chaîne est stockée de manière non contiguë, ce qui semble être le cas si la chaîne que vous traitez est en fait pontée vers NSString. Swift doit ensuite réassembler tous les tampons du tableau d'octets dans un seul tampon contigu et ce qui nécessite la création de nouveaux tampons en cours de route. et vous obtenez finalement un tampon contenant la chaîne que vous essayez de concaténer.En un mot, il y a 3 groupes de vérifications du compilateur qui vous ralentiront, c'est -à- dire que chaque sous-expression doit être reconsidérée à la lumière de tout ce qu'elle pourrait renvoyer . En conséquence, concaténer des chaînes avec interpolation, c'est-à-dire utiliser
" My fullName is \(firstName) \(LastName)"
est bien meilleur que"My firstName is" + firstName + LastName
puisque l'interpolation n'a pas de surchargeSwift 3 a apporté quelques améliorations. Pour plus d'informations, lisez Comment fusionner plusieurs tableaux sans ralentir le compilateur? . Néanmoins, l'
+
opérateur est toujours surchargé et il est préférable d'utiliser l'interpolation de chaîne pour les chaînes plus longuesUtilisation d'options (problème en cours - solution disponible)
Dans ce projet très simple:
Le temps de compilation des fonctions est comme tel:
Remarquez à quel point la durée de compilation
concatenatedOptionals
est folle .Cela peut être résolu en faisant:
qui compile en
88ms
La cause première du problème est que le compilateur n'identifie pas le
""
comme unString
. C'est en faitExpressibleByStringLiteral
Le compilateur verra
??
et devra parcourir tous les types qui se sont conformés à ce protocole , jusqu'à ce qu'il trouve un type qui peut être un type par défautString
. En utilisantemptyString
qui est codé en durString
, le compilateur n'a plus besoin de parcourir tous les types conformes deExpressibleByStringLiteral
Pour savoir comment enregistrer les temps de compilation, voir ici ou ici
Autres réponses similaires de Rob Napier sur SO:
Pourquoi l'ajout de chaînes prend si longtemps à construire?
Comment fusionner plusieurs tableaux sans ralentir le compilateur?
Swift Array contient une fonction qui prolonge les temps de construction
la source
C'est assez ridicule quoi que vous disiez! :)
Mais cela se passe facilement
la source
J'ai eu un problème similaire:
Dans Xcode 9.3, la ligne ressemble à ceci:
Après l'avoir changé en quelque chose comme ça:
tout a fonctionné.
Cela a probablement quelque chose à voir avec le compilateur Swift qui tente d'inférer le type de données à partir du code.
la source