ios - how - the swift programming language pdf
Erro do compilador Swift: “Expressão muito complexa” em uma concatenação de string (3)
Acho isso divertido mais do que tudo.
Eu consertei, mas estou pensando na causa.
Aqui está o erro:
DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
.
Por que está reclamando?
Parece uma das expressões mais simples possíveis.
O compilador aponta para as
columns + ");";
seção
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);
}
a correção é:
var statement = "create table if not exists " + self.tableName();
statement += "(" + columns + ");";
isso também funciona (via @efischency), mas eu não gosto muito porque acho que o
(
se perca:
var statement = "create table if not exists \(self.tableName()) (\(columns))"
Eu tive um problema semelhante:
expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
No Xcode 9.3, a linha é assim:
let media = entities.filter { (entity) -> Bool in
Depois de mudar para algo assim:
let media = entities.filter { (entity: Entity) -> Bool in
tudo deu certo.
Provavelmente tem algo a ver com o compilador Swift tentando inferir o tipo de dados do código ao redor.
Isso é quase o mesmo que a resposta aceita, mas com alguns diálogos adicionais (tive com Rob Napier, suas outras respostas e outro amigo de um encontro da Cocoahead) e links.
Veja os comentários this discussão. A essência disso é:
O
operador
+
está sobrecarregado, a partir de agora ele possui 27 funções diferentes; portanto, se você estiver concatenando 4 strings, ou seja, você tem 3
+
operadores, o compilador deve
verificar
entre 27 operadores a cada vez, ou seja, 27 ^ 3 vezes.
Mas não é isso.
Há também uma
check
para ver se os
lhs
e
rhs
das funções
+
são válidos se forem chamados para o núcleo do
append
chamado.
Lá você pode ver que existem várias
checks
intensivas que podem ocorrer.
Se a sequência for armazenada de forma não contígua, o que parece ser o caso se a sequência com a qual você está lidando for realmente conectada ao NSString.
O Swift precisa montar novamente todos os buffers da matriz de bytes em um único buffer contíguo, o que requer a criação de novos buffers ao longo do caminho.
e, eventualmente, você obtém um buffer que contém a string que você está tentando concatenar juntos.
Em poucas palavras, existem três grupos de verificações do compilador que o atrasarão, ou seja,
cada subexpressão deve ser reconsiderada à luz de tudo o que
possa
retornar
.
Como resultado, concatenar seqüências de caracteres com interpolação, ou seja, usar
" My fullName is \(firstName) \(LastName)"
é muito melhor que
"My firstName is" + firstName + LastName
pois a interpolação
não
possui sobrecarga
O Swift 3
fez
algumas
melhorias.
Para obter mais informações, leia
Como mesclar várias matrizes sem diminuir a velocidade do compilador?
.
No entanto, o operador
+
ainda está sobrecarregado e é melhor usar a interpolação de strings para strings mais longos
Outras respostas semelhantes de Rob Napier no SO:
Por que a adição de strings leva tanto tempo para construir?
Como mesclar várias matrizes sem diminuir a velocidade do compilador?
Swift Array contém a função que aumenta o tempo de construção
Não sou especialista em compiladores - não sei se essa resposta "mudará a maneira como você pensa de maneira significativa", mas meu entendimento do problema é o seguinte:
Tem a ver com inferência de tipo.
Cada vez que você usa o operador
+
, o Swift precisa pesquisar todas as sobrecargas possíveis para
+
e inferir qual versão do
+
você está usando.
Contei pouco menos de 30 sobrecargas para o operador
+
.
São muitas possibilidades e, quando você agrupa operações 4 ou 5
+
e pede ao compilador para inferir todos os argumentos, você está pedindo muito mais do que parece à primeira vista.
Essa inferência pode ser complicada - por exemplo, se você adicionar um
UInt8
e um
Int
usando
+
, a saída será um
Int
, mas há algum trabalho para avaliar as regras para misturar tipos com operadores.
E quando você está usando literais, como os literais
String
no seu exemplo, o compilador faz o trabalho de converter o literal
String
em uma
String
e, em seguida, realiza o trabalho de inferir os argumentos e os tipos de retorno para o operador
+
, etc.
Se uma expressão é suficientemente complexa - ou seja, requer que o compilador faça muitas inferências sobre os argumentos e os operadores - ela sai e informa que foi encerrada.
Ter o compilador encerrado quando uma expressão atingir um certo nível de complexidade é intencional. A alternativa é deixar o compilador tentar fazê-lo e ver se pode, mas isso é arriscado - o compilador pode continuar tentando para sempre, atolar ou simplesmente travar. Portanto, meu entendimento é que existe um limite estático para a complexidade de uma expressão que o compilador não irá além.
Meu entendimento é que a equipe Swift está trabalhando em otimizações de compilador que tornarão esses erros menos comuns. Você pode aprender um pouco sobre isso nos fóruns de desenvolvedores da Apple, clicando neste link .
Nos fóruns de desenvolvimento, Chris Lattner pediu às pessoas para arquivar esses erros como relatórios de radar, porque eles estão trabalhando ativamente para corrigi-los.
É assim que eu entendo depois de ler várias postagens aqui e no fórum do Dev sobre isso, mas meu entendimento dos compiladores é ingênuo e espero que alguém com um conhecimento mais profundo de como eles lidam com essas tarefas expanda o que eu escrevi aqui.