Esto me parece más divertido que nada. Lo arreglé, pero me pregunto por la causa. Aquí está el error: DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
. ¿Por qué se queja? Parece una de las expresiones más simples posibles.
El compilador apunta a la columns + ");";
sección
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);
}
la solución es:
var statement = "create table if not exists " + self.tableName();
statement += "(" + columns + ");";
esto también funciona (a través de @efischency) pero no me gusta tanto porque creo que (
se pierden:
var statement = "create table if not exists \(self.tableName()) (\(columns))"
ios
xcode
swift
compiler-errors
functional-programming
Kendrick Taylor
fuente
fuente
var statement = "create table if not exists \(self.tableName()) (\(columns))"
?+
.Respuestas:
No soy un experto en compiladores. No sé si esta respuesta "cambiará su forma de pensar de manera significativa", pero mi comprensión del problema es la siguiente:
Tiene que ver con la inferencia de tipos. Cada vez que usa el
+
operador, Swift tiene que buscar a través de todas las sobrecargas posibles+
e inferir qué versión de+
usted está usando. Conté poco menos de 30 sobrecargas para el+
operador. Esas son muchas posibilidades, y cuando encadena 4 o 5+
operaciones juntas y le pide al compilador que infiera todos los argumentos, está pidiendo mucho más de lo que podría parecer a primera vista.Esa inferencia puede complicarse; por ejemplo, si agrega un
UInt8
y unInt
uso+
, la salida será unInt
, pero hay algo de trabajo en evaluar las reglas para mezclar tipos con operadores.Y cuando usa literales, como los
String
literales en su ejemplo, el compilador realiza el trabajo de convertir elString
literal en aString
, y luego realiza el trabajo de inferir el argumento y los tipos de retorno para el+
operador, etc.Si una expresión es suficientemente compleja, es decir, requiere que el compilador haga demasiadas inferencias sobre los argumentos y los operadores, se cierra y le dice que se cierra.
Hacer que el compilador se cierre una vez que una expresión alcanza un cierto nivel de complejidad es intencional. La alternativa es dejar que el compilador lo intente y lo haga, y ver si puede, pero eso es arriesgado: el compilador podría seguir intentándolo para siempre, atascarse o simplemente bloquearse. Entonces, entiendo que hay un umbral estático para la complejidad de una expresión que el compilador no irá más allá.
Tengo entendido que el equipo de Swift está trabajando en las optimizaciones del compilador que harán que estos errores sean menos comunes. Puede aprender un poco al respecto en los foros de desarrolladores de Apple haciendo clic en este enlace .
En los foros de desarrollo, Chris Lattner ha pedido a las personas que presenten estos errores como informes de radar, porque están trabajando activamente para solucionarlos.
Así es como lo entiendo después de leer varias publicaciones aquí y en el foro de desarrollo al respecto, pero mi comprensión de los compiladores es ingenua, y espero que alguien con un conocimiento más profundo de cómo manejan estas tareas se expanda en lo que yo He escrito aquí.
fuente
Esto es casi lo mismo que la respuesta aceptada pero con un diálogo adicional (tuve con Rob Napier, sus otras respuestas y Matt, Oliver, David de Slack) y enlaces.
Ver los comentarios en esta discusión. La esencia de esto es:
+
está muy sobrecargado (Apple parece haber solucionado esto en algunos casos)El
+
operador está muy sobrecargado, a partir de ahora tiene 27 funciones diferentes, por lo que si está concatenando 4 cadenas, es decir, tiene 3+
operadores, el compilador debe verificar entre 27 operadores cada vez, por lo que es 27 ^ 3 veces. Pero eso no es todo.También hay una comprobación para ver si las funciones
lhs
yrhs
de+
ambas son válidas si son llamadas a través del núcleo de lasappend
llamadas. Allí puede ver que hay varias comprobaciones intensivas que pueden ocurrir. Si la cadena se almacena de forma no contigua, lo que parece ser el caso si la cadena con la que está tratando está realmente unida a NSString. Swift luego tiene que volver a ensamblar todos los búferes de matriz de bytes en un solo búfer contiguo y eso requiere crear nuevos búferes en el camino. y finalmente obtienes un búfer que contiene la cadena que estás intentando concatenar juntos.En pocas palabras, hay 3 grupos de comprobaciones del compilador que lo retrasarán, es decir, cada subexpresión debe reconsiderarse a la luz de todo lo que pueda devolver . Como resultado, la concatenación de cadenas con interpolación, es decir, el uso
" My fullName is \(firstName) \(LastName)"
es mucho mejor que"My firstName is" + firstName + LastName
dado que la interpolación no tiene ninguna sobrecargaSwift 3 ha realizado algunas mejoras. Para obtener más información, lea ¿Cómo fusionar varias matrices sin ralentizar el compilador? . No obstante, el
+
operador todavía está sobrecargado y es mejor utilizar la interpolación de cadenas para cadenas más largas.Uso de opcionales (problema continuo - solución disponible)
En este proyecto muy simple:
El tiempo de compilación de las funciones es el siguiente:
Observe cuán loca es la duración de la compilación
concatenatedOptionals
.Esto se puede resolver haciendo:
que compila en
88ms
La causa raíz del problema es que el compilador no identifica el
""
como aString
. En realidad esExpressibleByStringLiteral
El compilador verá
??
y tendrá que recorrer todos los tipos que se hayan conformado a este protocolo , hasta que encuentre un tipo que pueda ser el predeterminadoString
. Al usar elemptyString
que está codificadoString
, el compilador ya no necesita recorrer todos los tipos deExpressibleByStringLiteral
Para aprender cómo registrar tiempos de compilación, vea aquí o aquí
Otras respuestas similares de Rob Napier en SO:
¿Por qué la adición de cadenas tarda tanto en construirse?
¿Cómo fusionar varias matrices sin ralentizar el compilador?
Swift Array contiene función que hace que los tiempos de construcción sean largos
fuente
¡Esto es bastante ridículo sin importar lo que digas! :)
Pero esto se pasa fácilmente
fuente
Tuve un problema similar:
En Xcode 9.3 la línea es así:
Después de cambiarlo a algo como esto:
Todo salió bien.
Probablemente tenga algo que ver con el compilador Swift que intenta inferir el tipo de datos del código.
fuente