Ошибка компилятора Swift: "слишком сложное выражение" при конкатенации строк


Я нахожу это забавным, больше ничего. Я это исправил, но мне интересно, в чем причина. Вот ошибка:DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions. Почему он жалуется? Кажется, это одно из самых простых выражений.

компилятор указывает на columns + ");"; раздел

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);
}

исправления:

var statement = "create table if not exists " + self.tableName();
statement += "(" + columns + ");";

это также работает (через @efischency), но мне это не нравится, потому что я думаю, что ( заблудиться:

var statement = "create table if not exists (self.tableName()) ((columns))"

4 132

4 ответа:

Я не эксперт по компиляторам - я не знаю, будет ли этот ответ "изменить то, как вы думаете, значимым образом", но мое понимание проблемы таково:

это связано с типом вывода. Каждый раз, когда вы используете + оператор, Swift должен искать через все возможные перегрузки для + и сделать вывод, какая версия + вы используете. Я насчитал чуть менее 30 перегрузок для + оператора. Это много возможностей, и когда вы цепочка 4 или 5 + операции вместе и задать компилятору, чтобы вывести все аргументы, вы просите намного больше, чем может показаться на первый взгляд.

вывод может усложниться, например, если добавить UInt8 и Int используя +, будет Int, но есть некоторые работы, которые идут в оценке правил для смешивания типов с операторами.

и когда вы используете литералы, как String литералы в вашем примере компилятор делает работу по преобразованию String литерала String, а затем выполняет работу по выведению аргумента и возвращаемых типов для + оператор, etc.

если выражение достаточно сложное-т. е. оно требует от компилятора слишком много выводов о Аргументах и операторах - оно завершает работу и сообщает вам, что оно завершается.

если компилятор завершает работу, как только выражение достигает определенного уровня сложности, это преднамеренно. Этот альтернатива-позволить компилятору попытаться сделать это, и посмотреть, если он может, но это рискованно - компилятор может идти о попытке навсегда увязнуть, или просто аварии. Поэтому я понимаю, что существует статический порог сложности выражения, который компилятор не будет превышать.

Я понимаю, что команда Swift работает над оптимизацией компилятора, которая сделает эти ошибки менее распространенными. вы можете узнать немного об этом на форумах разработчиков Apple перейдя по этой ссылке.

на форумах разработчиков Крис Латтнер попросил людей подавать эти ошибки в качестве отчетов радара, потому что они активно работают над их исправлением.

вот как я понимаю это после прочтения ряда сообщений здесь и на форуме Dev об этом, но мое понимание компиляторов наивно, и я надеюсь, что кто-то с более глубоким знанием того, как они справляются с этими задачами, расширит то, что я написал здесь.

это почти то же самое, что и принятый ответ, но с некоторым добавленным диалогом (у меня был с Робом Нейпиром и другим другом из Cocoahead meetup) и ссылками.

см. комментарии этой обсуждение. Суть его такова:

The + оператор сильно перегружен, на данный момент он имеет 27 различных функций, так что если вы объединяете 4 строки т. е. у вас есть 3 + операторы компилятор должен Регистрация между 27 операторы каждый раз, так что это 27^3 раза. Но дело не в этом.

есть еще и Регистрация чтобы увидеть, если lhs и rhs на + функции оба действительны, если они являются его вызовы через ядро append называется. Там вы можете увидеть, что есть ряд несколько интенсивных проверки что может произойти. Если строка хранится несмежно, что, по-видимому, имеет место, если строка, с которой Вы имеете дело, является на самом деле мост к NSString. Затем Swift должен повторно собрать все буферы массива байтов в один непрерывный буфер, что требует создания новых буферов на этом пути. и тогда вы в конечном итоге сделать один буфер, содержащий строку, которую вы пытаетесь объединить.

в двух словах есть 3 кластера проверок компилятора, которые замедлят вас и, следовательно, сцепление строк с интерполяцией ie с помощью " My fullName is \(firstName) \(LastName)" намного лучше, чем "My firstName is" + firstName + LastName с интерполяцией не имеет никакой перегрузки

Swift 3 сделал некоторые улучшения. Для получения дополнительной информации читайте как объединить несколько массивов без замедления компилятора?

Это довольно смешно, что бы вы ни говорили! :)

enter image description here

но это быстро прошло

return "\(year) \(month) \(dayString) \(hour) \(min) \(weekDay)"

у меня была аналогичная проблема:

expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions

в Xcode 9.3 строка выглядит так:

let media = entities.filter { (entity) -> Bool in

после изменения его в нечто вроде этого:

let media = entities.filter { (entity: Entity) -> Bool in

все получилось.

вероятно, это как-то связано с компилятором Swift, пытающимся вывести тип данных из кода.