Doppio rapido per incordare


108

Prima di aggiornare xCode 6, non avevo problemi a lanciare un double su una stringa ma ora mi dà un errore

var a: Double = 1.5
var b: String = String(a)

Mi dà il messaggio di errore "double non è convertibile in stringa". c'è un altro modo per farlo?


5
Potrebbe anche essere utile definirlo comevar b = "\(a)"
erdekhayser

Risposte:


211

Non sta eseguendo il casting, sta creando una stringa da un valore con un formato.

let a: Double = 1.5
let b: String = String(format: "%f", a)

print("b: \(b)") // b: 1.500000

Con un formato diverso:

let c: String = String(format: "%.1f", a)

print("c: \(c)") // c: 1.5

È inoltre possibile omettere la formatproprietà se non è necessaria la formattazione.


1
Che ne dici di un doppio con un numero di cifre frazionario più grande? Come let a = 2.34934340320 let stringValue = String (format: "% f", a) darà 2.349343
Nico

1
Il display può essere controllato con le opzioni di formattazione printf, vedere: String Format Specifiers e printf (3) .
Zaf

2
Non vi resta che modificare il formato per controllare la quantità di cifre: format:"%.1f" = 1 digit // 1.5; format:"%.5f" = 5 digits // 1.50000
Megaetron

3
Aggiorna la tua risposta, in Swift 2.1 devi solo fare String(yourDouble).
Alexandre G.

1
Puoi usare let invece di var. Non è necessario chiamarlo ora più volte.
Oleksandr

81
let double = 1.5 
let string = double.description

aggiornare Xcode 7.1 • Swift 2.1:

Ora Double è anche convertibile in String, quindi puoi usarlo semplicemente come desideri:

let double = 1.5
let doubleString = String(double)   // "1.5"

Swift 3 o successivo possiamo estenderlo LosslessStringConvertiblee renderlo generico

Xcode 11.3 • Swift 5.1 o successivo

extension LosslessStringConvertible { 
    var string: String { .init(self) } 
}

let double = 1.5 
let string = double.string  //  "1.5"

Per un numero fisso di cifre frazionarie possiamo estendere il FloatingPointprotocollo:

extension FloatingPoint {
    func fixedFraction(digits: Int) -> String {
        return String(format: "%.*f", digits, self as! CVarArg)
    }
}

Se hai bisogno di un maggiore controllo sul formato del tuo numero (cifre frazionarie minime e massime e modalità di arrotondamento) puoi usare NumberFormatter:

extension Formatter {
    static let number = NumberFormatter()
}

extension FloatingPoint {
    func fractionDigits(min: Int = 2, max: Int = 2, roundingMode: NumberFormatter.RoundingMode = .halfEven) -> String {
        Formatter.number.minimumFractionDigits = min
        Formatter.number.maximumFractionDigits = max
        Formatter.number.roundingMode = roundingMode
        Formatter.number.numberStyle = .decimal
        return Formatter.number.string(for: self) ?? ""
    }
}

2.12345.fractionDigits()                                    // "2.12"
2.12345.fractionDigits(min: 3, max: 3, roundingMode: .up)   // "2.124"

1
è un hack o è un modo legittimo per farlo? potrebbe causare problemi con diverse versioni di iOS?
Esqarrouth

2
No, non avrai problemi con diverse versioni di iOS. Funziona anche per OSX. BTW questo è ciò che ottieni quando esegui l'interpolazione di stringhe con un Double o un Int.
Leo Dabus

Molto utile. Non puoi formattare come% f. E funziona anche per Int, quindi hai un modo per farlo per due tipi.
Patrik Vaberer

Questo non funzionerà per 0,00001, diventa "1e-05" come stringa.
Alex

Sostituisci String(format: "%.\(digits)f", self as! CVarArg)conString(format: "%.*f", digits, self as! CVarArg)
rmaddy

21

Oltre alla risposta di @Zaph, puoi creare extension:

extension Double {
    func toString() -> String {
        return String(format: "%.1f",self)
    }
}

Uso:

var a:Double = 1.5
println("output: \(a.toString())")  // output: 1.5

1
@MaximShoustin L'OP non ha abbastanza rappresentanti per votare e rispondere, 15 è richiesto. Inoltre non sono d'accordo con la creazione di un'estensione, quando l'affermazione: a.toString()viene vista da un altro sviluppatore ci sarà sicuramente un momento WTF.
Zaph

1
@ Zaph, perché no. Di sicuro puoi aggiungere un prefisso e cambiarlo myToString()per essere sicuro che la sua definizione personalizzata. Ma come in altri linguaggi la prototipazione porta ad evitare la duplicazione del codice e una buona manutenzione.
Maxim Shoustin

@ MaximShoustin domanda per principianti: qual è la differenza tra println("output: \(a.toString())")e println("output: \(a)"). La seconda opzione non causa errori di compilazione. Questa opzione è una cattiva pratica?
Alex Guerrero

Esiste un modo intelligente per scrivere un'estensione di questo tipo in Double o FloatingPoint che funzioni su un Double opzionale per restituire una stringa vuota?
Kinergy

@KinergyyourDouble?.toString() ?? ""
Leo Dabus

11

Swift 3+: prova queste righe di codice

let num: Double = 1.5

let str = String(format: "%.2f", num)

9

per rendere qualsiasi cosa una stringa in swift tranne forse i valori enum, fai semplicemente quello che fai nel metodo println ()

per esempio:

var stringOfDBL = "\(myDouble)"


3

Questa funzione ti consentirà di specificare il numero di posizioni decimali da mostrare:

func doubleToString(number:Double, numberOfDecimalPlaces:Int) -> String {
    return String(format:"%."+numberOfDecimalPlaces.description+"f", number)
}

Uso:

let numberString = doubleToStringDecimalPlacesWithDouble(number: x, numberOfDecimalPlaces: 2)

Sostituisci String(format:"%."+numberOfDecimalPlaces.description+"f", number)conString(format:"%.*f", numberOfDecimalPlaces, number)
rmaddy

3

Ci sono molte risposte qui che suggeriscono una varietà di tecniche. Ma quando si presentano numeri nell'interfaccia utente, si desidera sempre utilizzare a in NumberFormattermodo che i risultati siano formattati, arrotondati e localizzati correttamente:

let value = 10000.5

let formatter = NumberFormatter()
formatter.numberStyle = .decimal

guard let string = formatter.string(for: value) else { return }
print(string) // 10,000.5

Se si desidera un numero fisso di cifre decimali, ad esempio per i valori di valuta

let value = 10000.5

let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2

guard let string = formatter.string(for: value) else { return }
print(string) // 10,000.50

Ma la bellezza di questo approccio è che verrà localizzato correttamente, con il risultato 10,000.50negli Stati Uniti ma 10.000,50in Germania. Impostazioni locali diverse hanno formati preferiti diversi per i numeri e dovremmo consentire di NumberFormatterutilizzare il formato preferito dall'utente finale quando si presentano valori numerici all'interno dell'interfaccia utente.

Inutile dire che, sebbene NumberFormattersia essenziale quando si preparano rappresentazioni di stringhe all'interno dell'interfaccia utente, non dovrebbe essere utilizzato se si scrivono valori numerici come stringhe per l'archiviazione persistente, l'interfaccia con i servizi Web, ecc.


2
Questo dovrebbe essere contrassegnato come la risposta giusta
Asad Khan

2

In swift 3:

var a: Double = 1.5
var b: String = String(a)

1

In swift 3 è semplice come indicato di seguito

let stringDouble =  String(describing: double)

3
Questo restituisce ad esempio "Optional(6.1696108999999995)"per me.
McSullivan D'Ander

0
var b = String(stringInterpolationSegment: a)

Questo funziona per me. Potresti provare


0

In Swift 4, se desideri modificare e utilizzare un Double nell'interfaccia utente come un'etichetta di testo "String", puoi aggiungerla alla fine del file:

    extension Double {
func roundToInt() -> Int{
    return Int(Darwin.round(self))
}

}

E usalo in questo modo se ti piace averlo in un'etichetta di testo:

currentTemp.text = "\(weatherData.tempCelsius.roundToInt())"

Oppure stampalo come Int:

print(weatherData.tempCelsius.roundToInt())

0

Preferirei l'approccio NSNumber e NumberFormatter (dove necessario), inoltre puoi usare l'estensione per evitare il gonfiore del codice

extension Double {

   var toString: String {
      return NSNumber(value: self).stringValue
   }

}

Puoi anche aver bisogno di un approccio inverso

extension String {

    var toDouble: Double {
        return Double(self) ?? .nan
    }

}

perché stai restituendo opzionale ma assegnando .nan se nullo? Dovresti fare l'uno o l'altro. Non entrambi. Btw Cosa c'è di sbagliato nell'usare l'inizializzatore di stringhe? Puoi anche renderlo più generico estendendo il LossLessStringConvertibleprotocollo invece di estendere Double extension LosslessStringConvertible { var string: String { return .init(self) } }
Leo Dabus

Hai ragione di ritorno Double? È un rifiuto visto che già controllo che sia nullo e riconsegno NaN
Giuseppe Mazzilli

0

Swift 5 : usa il seguente codice

extension Double {

    func getStringValue(withFloatingPoints points: Int = 0) -> String {
        let valDouble = modf(self)
        let fractionalVal = (valDouble.1)
        if fractionalVal > 0 {
            return String(format: "%.*f", points, self)
        }
        return String(format: "%.0f", self)
    }
}

Sostituisci String(format: "%.\(points)f", self)conString(format: "%.*f", points, self)
rmaddy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.