Swift Derleyici Hatası: Dize birleştirmesinde “İfade çok karmaşık”


143

Bunu her şeyden çok eğlenceli buluyorum. Çözdüm, ama sebebini merak ediyorum. İşte hatadır: DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions. Neden şikayet ediyor? Mümkün olan en basit ifadelerden biri gibi görünüyor.

Derleyici columns + ");";bölümü gösterir

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

düzeltme:

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

Bu da (@efischency aracılığıyla) çalışır ama ben (kaybolmak düşünüyorum çünkü o kadar sevmiyorum :

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


10
Bunun işe yarayıp yaramadığını gördünüz mü var statement = "create table if not exists \(self.tableName()) (\(columns))"?
efischency

5
@Efischency tarafından önerildiği gibi dize enterpolasyonu, genellikle el ile birleştirmekten daha iyi bir seçenektir +.
mattt

5
Tabii, ama mesele bu değil. "Önerilen" yol olup olmadığı umurumda değil, sadece derleyicinin neden boğulduğunu bilmek istiyorum. Çalışan bir çözümüm var, hatayı düzeltmekle ilgili değil, hatayı anlamakla ilgili.
Kendrick Taylor

2
Duyduğum kadarıyla, Swift derleyici hala devam eden bir çalışma. Takım bununla ilgili bir hata raporunu takdir edebilir.
molbdnilo

6.3.1 ile derlerken sorun yaşamadım. Geçmişte benzer gülünç mesajlar aldım. Swift alfa durumunu terk edene kadar beklememiz gerekiyor.
qwerty_so

Yanıtlar:


183

Derleyiciler konusunda uzman değilim - bu cevabın "düşünme şeklinizi anlamlı bir şekilde değiştirip değiştirmeyeceğini" bilmiyorum ama problem hakkındaki anlayışım şudur:

Tür çıkarımı ile ilgilidir. +Operatörü her kullandığınızda , Swift tüm olası aşırı yüklenmeleri araştırmalı +ve hangi sürümü +kullandığınızı çıkarmalıdır . +Operatör için 30'dan fazla aşırı yük saydım . Bu çok fazla olasılık ve 4 veya 5 +işlemi bir araya getirip derleyiciden tüm argümanları çıkarmasını istediğinde, ilk bakışta göründüğünden çok daha fazlasını soruyorsun.

Bu çıkarsama karmaşık bir hale gelebilir - örneğin, bir eklerseniz UInt8ve Intkullanan +, çıkış bir olacak Int, ama operatörleri ile türlerini karıştırarak kurallarını değerlendirirken gider kısımlar da var.

StringÖrneğin örneğinizdeki değişmez değerler gibi değişmez değerleri kullandığınızda , derleyici Stringdeğişmez değeri a Stringdeğerine dönüştürme ve ardından +işleç için bağımsız değişken ve dönüş türlerini çıkarma işi yapar .

Bir ifade yeterince karmaşıksa - yani, derleyicinin argümanlar ve işleçler hakkında çok fazla çıkarım yapmasını gerektirir - bırakıp bıraktığını söyler.

Bir ifadenin belirli bir karmaşıklık düzeyine ulaştığında derleyicinin kapatılması kasıtlıdır. Alternatif, derleyicinin denemesine ve yapmasına izin vermek ve yapabilir mi, ancak bu riskli - derleyici sonsuza kadar denemeye, bataklığa veya sadece çökmeye devam edebilir. Benim anlayışım, derleyicinin ötesine geçmeyeceği bir ifadenin karmaşıklığı için statik bir eşik olduğudur.

Anladığım kadarıyla Swift ekibi, bu hataları daha az yaygın hale getirecek derleyici optimizasyonları üzerinde çalışıyor. Bu bağlantıyı tıklayarak Apple Geliştirici forumlarında biraz bilgi edinebilirsiniz .

Geliştirici forumlarında Chris Lattner, bu hataları radar raporları olarak dosyalamalarını istedi, çünkü aktif olarak bunları düzeltmek için çalışıyorlar.

Buradaki ve Dev forumundaki bir dizi mesajı okuduktan sonra bunu anlıyorum, ancak derleyici anlayışım naif ve umarım bu görevleri nasıl ele aldıkları hakkında daha derin bilgiye sahip birisinin burada yazmışlar.


Bu konuda bir şeyler düşündüm, ama daha az yardımcı olan bir cevaptı. Cevapladığınız için teşekkürler. + Operatör sayısını elle mi saydınız yoksa farkında olmadığım kaygan bir yol var mı?
Kendrick Taylor

SwiftDoc.org'da bir göz attım ve onları elle saydım. Bu benim bahsettiğim sayfa: swiftdoc.org/operator/pls
Aaron Rasmussen

28
Bu bir hata, buna böyle adlandırıp adlandırmayacaklarına bakılmaksızın. Diğer dillerin derleyicilerinin gönderilenlere benzer kodlarla ilgili bir sorunu yoktur. Son kullanıcının bunu düzeltmesini önermek aptalca.
John

7
Tür çıkarımı? Swift gibi güçlü yazılan bir dile sahip olmanın anlamı nedir (içinde Int'yi kullanmadan String + Int'yi birleştiremezsiniz)? Swift bir kez daha hiç kimsenin sahip olmadığı sorunları çözmeye çalışıyor.
Azurlake

10
@John Hata değil, bana sorarsanız sadece kötü dil tasarımı! Swift çok farklı olmaya çalışıyor.
T. Rex

31

Bu neredeyse kabul edilen cevapla aynı ama bazı ek diyaloglarla (Rob Napier, diğer cevapları ve Matt, Oliver, David, Slack ile) ve bağlantılarla.

Bu tartışmadaki yorumlara bakın . Bunun özü:

+ aşırı yüklenmiş (Apple bazı durumlarda bunu düzeltmiş gibi görünüyor)

+Operatör size 4 dizeleri yani birleştirerek yüzden eğer 27 farklı işlevlere sahiptir bugün itibariyle ağır sen 3 var, aşırı yüklendi +derleyici zorundadır operatörleri kontrol o 27 ^ 3 kez bu yüzden, 27 operatörler her zaman arasındadır. Ama bu değil.

Bir de bulunmaktadır onay olmadığını görmek için lhsve rhsbir +fonksiyonlarına onlar çekirdeği içinden çağrıları ise hem geçerlidir appenddenir. Orada meydana gelebilecek biraz yoğun kontroller olduğunu görebilirsiniz. Dize bitişik olmayan bir şekilde depolanırsa, ele aldığınız dize aslında NSString ile köprülenirse durum böyle görünür. Swift daha sonra tüm bayt dizi tamponlarını tek bir bitişik tamponda yeniden birleştirmek zorundadır ve bu da yol boyunca yeni tamponlar oluşturmayı gerektirir. ve sonunda bir araya getirmeye çalıştığınız dizeyi içeren bir arabellek alırsınız.

Özetle, yani sizi yavaşlatır derleyici çeklerin 3 kümeleri vardır her alt ifadesi her şeyin ışık tekrar düşünülmesi gerekir olabilir dönmek . Sonuç olarak, enterpolasyon ile dizeleri birleştirmek, yani enterpolasyonun aşırı yüklenmesi olmadığından" My fullName is \(firstName) \(LastName)" çok daha iyidir"My firstName is" + firstName + LastName

Swift 3 yaptı bazı iyileştirmeler. Daha fazla bilgi için Derleyiciyi yavaşlatmadan birden çok Diziyi nasıl birleştirebilirim? Başlıklı konuyu okuyun. . Bununla birlikte, +operatör hala aşırı yüklenmiş ve daha uzun dizeler için dize enterpolasyonu kullanmak daha iyidir


Opsiyonel kullanım (devam eden problem - çözüm mevcut)

Bu çok basit projede:

import UIKit

class ViewController: UIViewController {

    let p = Person()
    let p2 = Person2()

    func concatenatedOptionals() -> String {
        return (p2.firstName ?? "") + "" + (p2.lastName ?? "") + (p2.status ?? "")
    }

    func interpolationOptionals() -> String {
        return "\(p2.firstName ?? "") \(p2.lastName ?? "")\(p2.status ?? "")"
    }

    func concatenatedNonOptionals() -> String {
        return (p.firstName) + "" + (p.lastName) + (p.status)
    }

    func interpolatedNonOptionals() -> String {
        return "\(p.firstName) \(p.lastName)\(p.status)"
    }
}


struct Person {
    var firstName = "Swift"
    var lastName = "Honey"
    var status = "Married"
}

struct Person2 {
    var firstName: String? = "Swift"
    var lastName: String? = "Honey"
    var status: String? = "Married"
}

Fonksiyonlar için derleme zamanı şöyledir:

21664.28ms  /Users/Honey/Documents/Learning/Foundational/CompileTime/CompileTime/ViewController.swift:16:10 instance method concatenatedOptionals()
2.31ms  /Users/Honey/Documents/Learning/Foundational/CompileTime/CompileTime/ViewController.swift:20:10 instance method interpolationOptionals()
0.96ms  /Users/Honey/Documents/Learning/Foundational/CompileTime/CompileTime/ViewController.swift:24:10 instance method concatenatedNonOptionals()
0.82ms  /Users/Honey/Documents/Learning/Foundational/CompileTime/CompileTime/ViewController.swift:28:10 instance method interpolatedNonOptionals()

Derleme süresinin ne kadar çılgın olduğuna dikkat edin concatenatedOptionals.

Bu, şu şekilde çözülebilir:

let emptyString: String = ""
func concatenatedOptionals() -> String {
    return (p2.firstName ?? emptyString) + emptyString + (p2.lastName ?? emptyString) + (p2.status ?? emptyString)
}

hangi derler 88ms

Sorunun temel nedeni, derleyicinin ""bir String. AslındaExpressibleByStringLiteral

Derleyici, varsayılan olabilen bir tür bulana kadar bu protokole uyan tüm türleri görecek ??ve bu döngüler arasında döngü yapacaktır String. Kullanarak emptyStringiçin kodlanmış olan String, derleyici artık tüm uygun türleri arasında döngü gerekiyorExpressibleByStringLiteral

Derleme sürelerinin nasıl günlüğe kaydedileceğini öğrenmek için buraya veya buraya bakın


Rob Napier on SO diğer benzer cevaplar:

Dize eklemenin oluşturulması neden bu kadar uzun sürüyor?

Derleyiciyi yavaşlatmadan çoklu Diziler nasıl birleştirilir?

Swift Array, oluşturma sürelerini uzatan bir işlev içerir


19

Ne derse desin bu çok saçma! :)

resim açıklamasını buraya girin

Ama bu kolayca geçiyor

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

2

Benzer bir sorunum vardı:

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

Xcode 9.3 satırında şöyle gider:

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

Böyle bir şeye değiştirdikten sonra:

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

her şey yolunda gitti.

Muhtemelen Swift derleyicisinin etrafındaki koddan veri türünü çıkarmaya çalıştığı bir şey var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.