Szybkie podwójne do sznurka

108

Zanim zaktualizowałem xCode 6, nie miałem problemów z rzutowaniem double na ciąg, ale teraz wyświetla mi się błąd

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

Daje mi komunikat o błędzie „double nie da się zamienić na łańcuch”. Czy jest na to inny sposób?

tim_yng
źródło
5
Przydatne może być również zdefiniowanie tego w następujący sposóbvar b = "\(a)"
erdekhayser

Odpowiedzi:

211

Nie jest rzutowaniem, ale tworzeniem łańcucha z wartości o określonym formacie.

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

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

W innym formacie:

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

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

Możesz również pominąć tę formatwłaściwość, jeśli formatowanie nie jest potrzebne.

uff
źródło
1
A co z podwójnym z większą liczbą cyfr ułamkowych? Na przykład niech a = 2.34934340320 let stringValue = String (format: "% f", a) da 2.349343
Nico
1
Wyświetlaniem można sterować za pomocą opcji formatowania printf, patrz: Specyfikatory formatu ciągu i printf (3) .
zaph
2
Po prostu trzeba zmienić format, aby kontrolować ilość cyfr: format:"%.1f" = 1 digit // 1.5; format:"%.5f" = 5 digits // 1.50000
Megaetron,
3
Zaktualizuj swoją odpowiedź, w Swift 2.1 po prostu musisz to zrobić String(yourDouble).
Alexandre G.
1
Możesz użyć let zamiast var. Nie ma teraz potrzeby, aby dzwonić do tego kilka razy.
Oleksandr
81
let double = 1.5 
let string = double.description

zaktualizuj Xcode 7.1 • Swift 2.1:

Teraz Double można również zamienić na String, więc możesz go po prostu używać, jak chcesz:

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

Swift 3 lub nowszy możemy rozszerzyć LosslessStringConvertiblei uczynić go ogólnym

Xcode 11.3 • Swift 5.1 lub nowszy

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

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

Dla ustalonej liczby cyfr ułamkowych możemy rozszerzyć FloatingPointprotokół:

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

Jeśli potrzebujesz większej kontroli nad formatem liczb (minimalne i maksymalne cyfry ułamkowe oraz tryb zaokrąglania), możesz użyć 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"
Leo Dabus
źródło
1
czy to hack, czy jest to legalny sposób, aby to zrobić? czy spowodowałoby to jakieś problemy z różnymi wersjami iOS?
Esqarrouth
2
Nie, nie będziesz mieć żadnych problemów z różnymi wersjami iOS. Działa również na OSX. BTW to właśnie otrzymujesz, wykonując interpolację ciągów za pomocą Double lub Int.
Leo Dabus
Bardzo przydatne. Nie możesz formatować jak% f. Działa również dla Int, więc masz jeden sposób na zrobienie tego dla dwóch typów.
Patrik Vaberer
To nie zadziała dla 0,00001, zmieni się na „1e-05” jako ciąg.
Alex
Wymienić String(format: "%.\(digits)f", self as! CVarArg)zString(format: "%.*f", digits, self as! CVarArg)
rmaddy
21

Oprócz odpowiedzi @Zaph możesz tworzyć extension:

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

Stosowanie:

var a:Double = 1.5
println("output: \(a.toString())")  // output: 1.5
Maxim Shoustin
źródło
1
@MaximShoustin OP nie ma wystarczającej liczby przedstawicieli, aby głosować i odpowiadać, 15 jest wymaganych. Nie zgadzam się też z tworzeniem Rozszerzenia, gdy stwierdzenie: a.toString()zobaczy inny programista, na pewno będzie moment WTF.
zaph
1
@Zaph dlaczego nie. Na pewno możesz dodać jakiś prefiks i zmienić go, myToString()aby mieć pewność, że jest to niestandardowa definicja. Ale podobnie jak w innych językach, prototypowanie prowadzi do uniknięcia powielania kodu i dobrej konserwacji.
Maxim Shoustin
@MaximShoustin newbie question: jaka jest różnica między println("output: \(a.toString())")i println("output: \(a)"). Druga opcja nie powoduje błędów kompilacji. Czy ta opcja jest złą praktyką?
Alex Guerrero
Czy istnieje sprytny sposób na napisanie takiego rozszerzenia Double lub FloatingPoint, które działałoby na opcjonalnym Double, aby zwrócić pusty ciąg?
Kinergy
@KinergyyourDouble?.toString() ?? ""
Leo Dabus
11

Swift 3+: wypróbuj ten wiersz kodu

let num: Double = 1.5

let str = String(format: "%.2f", num)
Shiv Kumar
źródło
9

aby coś stało się ciągiem w swift, z wyjątkiem być może wartości wyliczeniowych, po prostu zrób to, co robisz w metodzie println ()

na przykład:

var stringOfDBL = "\(myDouble)"
eric bob
źródło
3

Swift 4 : Użyj następującego kodu

let number = 2.4
let string = String(format: "%.2f", number)
Abhishek Jain
źródło
1
To to samo rozwiązanie, które podał @ shiv-kumar stackoverflow.com/a/46487485/2227743
Eric Aya
3

Ta funkcja umożliwia określenie liczby miejsc dziesiętnych do wyświetlenia:

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

Stosowanie:

let numberString = doubleToStringDecimalPlacesWithDouble(number: x, numberOfDecimalPlaces: 2)
MobileMon
źródło
Wymienić String(format:"%."+numberOfDecimalPlaces.description+"f", number)zString(format:"%.*f", numberOfDecimalPlaces, number)
rmaddy
3

Istnieje wiele odpowiedzi, które sugerują różne techniki. Ale podczas prezentowania liczb w interfejsie użytkownika zawsze chcesz użyć znaku a, NumberFormatteraby wyniki były odpowiednio sformatowane, zaokrąglone i zlokalizowane:

let value = 10000.5

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

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

Jeśli chcesz mieć stałą liczbę miejsc dziesiętnych, np. Dla wartości walut

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

Ale piękno tego podejścia polega na tym, że będzie ono odpowiednio zlokalizowane, co spowoduje, że w 10,000.50USA, ale 10.000,50w Niemczech. Różne lokalizacje mają różne preferowane formaty liczb i powinniśmy pozwolić na NumberFormatterużycie formatu preferowanego przez użytkownika końcowego podczas prezentowania wartości liczbowych w interfejsie użytkownika.

Nie trzeba dodawać, że chociaż NumberFormatterjest niezbędny podczas przygotowywania reprezentacji ciągów w interfejsie użytkownika, nie powinien być używany w przypadku zapisywania wartości liczbowych jako ciągów do trwałego przechowywania, interfejsu z usługami sieciowymi itp.

Obrabować
źródło
2
To powinno być oznaczone jako prawidłowa odpowiedź
Asad Khan
2

W Swift 3:

var a: Double = 1.5
var b: String = String(a)
Carlson
źródło
1

W Swift 3 jest to proste, jak podano poniżej

let stringDouble =  String(describing: double)
Sebin Roy
źródło
3
To wraca np. "Optional(6.1696108999999995)"Dla mnie.
McSullivan D'Ander
0
var b = String(stringInterpolationSegment: a)

To działa dla mnie. Możesz spróbować

sevenkplus
źródło
0

W Swift 4, jeśli chcesz modyfikować i używać Double w interfejsie użytkownika jako textLabel „String”, możesz dodać to na końcu swojego pliku:

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

}

I użyj tego w ten sposób, jeśli chcesz mieć to na etykiecie tekstowej:

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

Lub wydrukuj jako Int:

print(weatherData.tempCelsius.roundToInt())
Patrik Rikama-Hinnenberg
źródło
0

Wolałbym podejście NSNumber i NumberFormatter (w razie potrzeby), a także możesz użyć rozszerzenia, aby uniknąć wzdęcia kodu

extension Double {

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

}

Możesz również potrzebować odwrotnego podejścia

extension String {

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

}
Giuseppe Mazzilli
źródło
dlaczego zwracasz opcjonalne, ale przypisujesz .nan, jeśli nil? Powinieneś zrobić jedno lub drugie. Nie obie. Przy okazji, co złego w używaniu inicjatora String? Możesz także uczynić go bardziej ogólnym rozszerzającym LossLessStringConvertibleprotokołem zamiast rozszerzania Double extension LosslessStringConvertible { var string: String { return .init(self) } }
Leo Dabus
Czy masz rację powracając Double? To odmowa, ponieważ już sprawdzam, czy jest zero i
zwracam
0

Swift 5 : Użyj następującego kodu

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)
    }
}
g212gs
źródło
Wymienić String(format: "%.\(points)f", self)zString(format: "%.*f", points, self)
rmaddy