Швидкий подвійний на рядок


108

До того, як я оновлював xCode 6, у мене не було проблем з підведенням двійника до рядка, але тепер це дає мені помилку

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

Це дає мені повідомлення про помилку "подвійний не перетворюється в рядок". Чи є якийсь інший спосіб зробити це?


5
Можливо, також буде корисно просто визначити це якvar b = "\(a)"
erdekhayser

Відповіді:


211

Це не кастинг, це створення рядка зі значення з форматом.

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

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

З іншим форматом:

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

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

Ви також можете опустити formatвластивість, якщо форматування не потрібно.


1
А як щодо подвійного з більшим числом дробів? Нехай a = 2.34934340320 нехай stringValue = String (формат: "% f", a) дасть 2.349343
Ніко

1
Дисплей можна керувати за допомогою параметрів форматування printf, див .: Специфікатори формату рядків та printf (3) .
заф

2
Вам просто потрібно змінити формат, щоб контролювати кількість цифр format:"%.1f" = 1 digit // 1.5:; format:"%.5f" = 5 digits // 1.50000
Мегаетрон

3
Будь ласка, оновіть свою відповідь, у Swift 2.1 ви просто повинні це зробити String(yourDouble).
Олександр Георгійович

1
Ви можете використовувати let замість var. Зараз не потрібно телефонувати кілька разів.
Олександр

81
let double = 1.5 
let string = double.description

оновлення Xcode 7.1 • Swift 2.1:

Тепер Double також можна конвертувати в String, тому ви можете просто використовувати його як завгодно:

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

Swift 3 або пізнішої версії ми можемо розширити LosslessStringConvertibleі зробити це загальним

Xcode 11.3 • Swift 5.1 або новішої версії

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

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

Для фіксованої кількості цифр дробу ми можемо розширити FloatingPointпротокол:

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

Якщо вам потрібно більше контролювати формат чисел (мінімальні та максимальні цифри дробу та режим округлення), ви можете використовувати 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
це хак чи це законний спосіб це зробити? це спричинило б проблеми з різними версіями ios?
Ескароут

2
Ні, у вас не буде проблем з різними версіями ios. Він також працює для OSX. BTW - це те, що ви отримуєте, роблячи String Interpolation з подвійним або Int.
Лев Дабус

Дуже корисний. Ви не можете форматувати, як% f. І це працює також для Int, тому у вас є один спосіб зробити це для двох типів.
Патрік Ваберер

Це не працюватиме 0,00001, воно стає "1e-05" як рядок.
Алекс

Замінити String(format: "%.\(digits)f", self as! CVarArg)наString(format: "%.*f", digits, self as! CVarArg)
rmaddy

21

Окрім @Zaph відповіді, ви можете створити extension:

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

Використання:

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

1
@MaximShoustin В ОП недостатньо представників, щоб проголосувати і відповісти, потрібно 15. Я також не згоден зі створенням розширення, коли твердження: a.toString()бачиться іншим розробником, безумовно, буде момент WTF.
zaph

1
@Zaph чому б ні. Напевно ви можете додати якийсь префікс і змінити його, щоб myToString()переконатися, що його власне визначення. Але, як і в інших мовах, прототипування призводить до уникнення дублювання коду та хорошого обслуговування.
Максим Шустін

Питання для початківців @MaximShoustin: в чому різниця між println("output: \(a.toString())")і println("output: \(a)"). Другий варіант не викликає помилок компіляції. Це варіант погана практика?
Алекс Герреро

Чи є розумний спосіб написати таке розширення в Double або FloatingPoint, яке б працювало на необов'язковому подвійному для повернення порожнього рядка?
Кінергі

@KinergyyourDouble?.toString() ?? ""
Лев Дабус


9

щоб швидко зробити що-небудь рядок, за винятком, можливо, значення перерахунків просто робити те, що ви робите в методі println ()

наприклад:

var stringOfDBL = "\(myDouble)"


3

Ця функція дозволить вам вказати кількість десяткових знаків для показу:

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

Використання:

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

Замінити String(format:"%."+numberOfDecimalPlaces.description+"f", number)наString(format:"%.*f", numberOfDecimalPlaces, number)
rmaddy

3

Тут є багато відповідей, які підказують різноманітні методи. Але, представляючи числа в інтерфейсі користувача, ви завжди хочете використовувати NumberFormatterтак, щоб результати були правильно відформатовані, округлені та локалізовані:

let value = 10000.5

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

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

Якщо потрібно фіксовану кількість десяткових знаків, наприклад, для значень валюти

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

Але краса цього підходу полягає в тому, що він буде належним чином локалізований, що призводить 10,000.50до США, але 10.000,50Німеччини. У різних локалях є різні бажані формати для чисел, і ми повинні дозволити NumberFormatterвикористовувати формат, бажаний кінцевим користувачем, представляючи числові значення в інтерфейсі користувача.

Потрібно сказати, що, хоча NumberFormatterце є важливим при підготовці представлення рядків в інтерфейсі, він не повинен використовуватися, якщо записувати числові значення як рядки для постійного зберігання, інтерфейсу з веб-службами тощо.


2
Це слід позначити як правильну відповідь
Асад Хан




0

У Swift 4, якщо ви хочете змінювати та використовувати Double в інтерфейсі як textLabel "String", ви можете додати це в кінці вашого файлу:

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

}

І використовуйте його так, якщо ви хочете мати його на текстовому ярлику:

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

Або роздрукуйте його як Int:

print(weatherData.tempCelsius.roundToInt())

0

Я вважаю за краще підхід NSNumber і NumberFormatter (де потрібно), також ви можете використовувати розширення, щоб уникнути здуття коду

extension Double {

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

}

Ви також можете потребувати зворотного підходу

extension String {

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

}

чому ви повертаєтеся необов’язково, але присвоюєте .nan якщо нуль? Ви повинні робити те чи інше. Не обоє. Btw Що не так у використанні ініціалізатора String? Ви також можете зробити це більш загальним LossLessStringConvertibleпротоколом розширення замість того, щоб продовжувати Double extension LosslessStringConvertible { var string: String { return .init(self) } }
Лео Дабус

Ви маєте право повертатися Подвійний? Це відмова, оскільки я вже перевіряю, що це нуль, і повернути NaN
Джузеппе

0

Swift 5 : Використовуйте наступний код

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

Замінити String(format: "%.\(points)f", self)наString(format: "%.*f", points, self)
rmaddy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.