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?


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.


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"

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

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)

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)"


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)

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.


2
To powinno być oznaczone jako prawidłowa odpowiedź
Asad Khan



0
var b = String(stringInterpolationSegment: a)

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


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())

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
    }

}

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

Wymienić String(format: "%.\(points)f", self)zString(format: "%.*f", points, self)
rmaddy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.