2015-08-27 14 views
12

Stavo dando un'occhiata allo docs e ho trovato StaticString. Essa afferma:Differenza tra stringa e StaticString

An simple string designed to represent text that is "knowable at compile-time".

Ho inizialmente pensato che String ha lo stesso comportamento NSString, che è noto al momento della compilazione, ma sembra che mi sbagliavo. Quindi la mia domanda è quando dovremmo usare StaticString invece di un String, ed è l'unica differenza è che StaticString è noto in fase di compilazione?

Una cosa che ho trovato è

var a: String = "asdf" //"asdf" 
var b: StaticString = "adsf" //{(Opaque Value), (Opaque Value), (Opaque Value)} 

sizeofValue(a) //24 
sizeofValue(b) //17 

modo che appaia come StaticString ha un po 'meno ingombro di memoria.

risposta

2

Sembra che StaticString possa contenere stringhe letterali. Non è possibile assegnare una variabile di tipo String ad esso e non può essere modificata (ad esempio con +=).

"Sapibile in fase di compilazione" non significa che il valore mantenuto dalla variabile verrà determinato al momento della compilazione, solo che qualsiasi valore assegnato ad esso è noto al momento della compilazione.

Si consideri l'esempio che funziona:

var str: StaticString 

for _ in 1...10 { 
    switch arc4random_uniform(3) { 
    case 0: str = "zero" 
    case 1: str = "one" 
    case 2: str = "two" 
    default: str = "default" 
    } 
    print(str) 
} 

Ogni volta che si può dare Swift ulteriori informazioni su come una variabile deve essere utilizzato, si può ottimizzare il codice di utilizzarlo. Limitando una variabile a StaticString, Swift sa che la variabile non verrà modificata, quindi potrebbe essere in grado di memorizzarla in modo più efficiente o accedere ai singoli caratteri in modo più efficiente.

Infatti, StaticString potrebbe essere implementato con solo un puntatore dell'indirizzo e una lunghezza. L'indirizzo a cui punta è solo la posizione nel codice statico in cui è definita la stringa. A StaticString non è necessario fare il conteggio dei riferimenti poiché non è (necessario) esistere nell'heap. Non è né assegnato né deallocato, quindi non è necessario il conteggio dei riferimenti.

"Consapevole in fase di compilazione" è piuttosto rigido. Anche questo non funziona:

let str: StaticString = "hello " + "world" 

che non riesce con l'errore:

error: 'String' is not convertible to 'StaticString'

+0

Sono un po 'confuso riguardo "il valore detenuto dalla variabile sarà determinato al momento della compilazione, solo che qualsiasi valore assegnato ad esso è conoscibile al momento della compilazione." Qual è allora la differenza tra conoscibile al momento della compilazione e determinata in fase di compilazione? E 'StaticString's non può essere mutato, tuttavia possono essere riassegnati pure. Quindi in pratica il compilatore non può essere sicuro del suo valore. –

+0

Il compilatore non sa quale valore una variabile di tipo 'StaticString' manterrà in fase di compilazione, ma sa che qualsiasi valore che verrà assegnato a quella variabile è un letterale di stringa che era noto al momento della compilazione. Quello che Swift farà con queste informazioni è noto solo agli autori di Swift fino a quando non rilasceranno il codice open source. – vacawama

+0

grazie per il chiarimento! –

4

StaticString è conoscibile al momento della compilazione. Questo può portare a ottimizzazioni. Esempio:

EDIT: Questa parte non funziona, vedere modifica sotto

Supponiamo di avere una funzione che calcola un Int per alcuni String valori per alcune costanti che si definiscono al momento della compilazione.

let someString = "Test" 
let otherString = "Hello there" 

func numberForString(string: String) -> Int { 
    return string.stringValue.unicodeScalars.reduce(0) { $0 * 1 << 8 + Int($1.value) } 
} 

let some = numberForString(someString) 
let other = numberForString(otherString) 

In questo modo, la funzione vengono eseguite con le "Test" e "Ciao a tutti" quando in realtà viene richiamato nel programma, quando l'applicazione si avvia per esempio. Sicuramente in fase di esecuzione.Tuttavia, se si modifica la funzione di prendere una StaticString

func numberForString(string: StaticString) -> Int { 
    return string.stringValue.unicodeScalars.reduce(0) { $0 * 1 << 8 + Int($1.value) } 
} 

il compilatore sa che il passato in StaticString è conoscibile al momento della compilazione, quindi indovinate cosa fa? Esegue la funzione proprio al momento della compilazione (Quanto è fantastico!). Una volta ho letto un articolo a riguardo, l'autore ha ispezionato l'assemblaggio generato e ha effettivamente trovato i numeri già calcolati.

Come si può vedere questo può essere utile in alcuni casi come quello menzionato, per non ridurre le prestazioni di runtime per cose che possono essere fatte in fase di compilazione.

MODIFICA: Dániel Nagy e me had a conversation. L'esempio precedente non funziona perché la funzione stringValue di StaticString non può essere conosciuta in fase di compilazione (perché restituisce un valore String). Ecco un esempio migliore:

func countStatic(string: StaticString) -> Int { 
    return string.byteSize // Breakpoint here 
} 

func count(string: String) -> Int { 
    return string.characters.count // Breakpoint here 
} 

let staticString : StaticString = "static string" 
let string : String = "string" 


print(countStatic(staticString)) 
print(count(string)) 

In una build di rilascio solo il secondo punto di interruzione viene innescato mentre se si cambia la prima funzione a

func countStatic(string: StaticString) -> Int { 
    return string.stringValue.characters.count // Breakpoint here 
} 

entrambi i punti di interruzione vengono attivati.

Apparentemente ci sono alcuni metodi che possono essere fatti in fase di compilazione mentre altri non possono. Mi chiedo come il compilatore calcoli questo in realtà.

+0

Quindi, in pratica, quando eseguo il debugging e inserisco un breakpoint nella funzione che utilizza 'StaticString', non dovrebbe nemmeno inserirlo? –

+0

@ DánielNagy Hmm Non lo so, forse viene catturato durante la compilazione, puoi provarlo suppongo che lo abbia provato – Kametrixom

+0

e avevi ragione! Ma puoi completare la risposta con una piccola aggiunta? Ho usato questo: func test() -> String { return StaticString (stringLiteral: "hejj"). StringaValue } metodo per testare ciò che hai affermato, inserire un breakpoint e vedere cosa sta succedendo. L'ottimizzazione del compilatore Swift predefinita è None, ma se la si modifica su Fastest o Fastest, Deschecked, il valore compilato è stato inserito, quindi il programma non si è fermato al breakpont. Quindi puoi aggiungere queste modifiche all'ottimizzazione del compilatore Swift alla tua risposta? –