Reputation: 5345
I'm attempting to convert a value to a string in an init
. That value can be an Int
, Double
, or Float
.
For example:
struct example {
var string: String
init(number: Int) {
string = String(number)
}
}
I would like to say something like below (I'm using Typescript as an example - this obviously doesn't work, but I want number to be any of those three types - all of which String
can convert).
struct example {
var string: String
init(number: Int | Float | Double) {
string = String(number)
}
}
Edit: I realized I have another issue. I need to convert back from a string to the type of Int or Double or Float. Using one of the answers below, I'm trying to figure out how to implement getNumberWith5
:
struct example2<N: Numeric & CustomStringConvertible>: CustomStringConvertible {
@Binding var number: N
init(number: Binding<N>) {
self._number = number
}
var description: String {
String(describing: number)
}
mutating func getNumberWith5() {
// How do I update number to the type N?
self.number = howDoIConvertToN(description + "5")
}
}
Or from another answer:
struct example3<N: Numeric> {
@Binding var number: N
var string: String
init(number: Binding<N>) {
self._number = number
self.string = "\(number)"
}
mutating func getNumberWith5() {
// How do I update number to the type N?
self.number = howDoIConvertToN(string + "5")
}
}
Edit2 My Answer:
I attempted to create an equivalent of type unions (as Typescript has) using enums
in Swift based on this article. But it was challenging to then assign back to that value. I've decided Swift just doesn't have first class support for type unions like Typescript has. So, I used the accepted answer below and this seems to work.
extension String {
func numeric<N: Numeric & LosslessStringConvertible>() -> N? {
N(self)
}
}
struct example4<N: Numeric & LosslessStringConvertible> {
@State var string: String
@Binding var number: N
init(number: Binding<N>) {
self._number = number
self.string = String(describing: number)
}
mutating func getNumberWith5() {
let newString = string + "5"
number = newString.numeric() ?? 0
}
}
Upvotes: 2
Views: 1301
Reputation: 2661
Actually if all you want is a string representation of Int
Float
Double
or any other standard numeric type you only need to know that they conform to CustomStringConvertible
and use String(describing:)
.
Or you can use conformance to Numeric
and CustomStringConvertible
:
struct example {
var string: String
init<C: CustomStringConvertible & Numeric>(number: C) {
string = String(describing: number)
}
}
and maybe even better example
itself could conform to CustomStringConvertible
struct example: CustomStringConvertible {
var description: String
init<C: CustomStringConvertible & Numeric>(number: C) {
description = String(describing: number)
}
}
yet another way :
struct example<N: Numeric & CustomStringConvertible>: CustomStringConvertible {
let number: N
init(number: N) {
self.number = number
}
var description: String {
String(describing: number)
}
}
I think what you want is a custom Property Wrapper not @Binding
:
@propertyWrapper struct CustomStringConversion<Wrapped: CustomStringConvertible> {
var wrappedValue: Wrapped
init(wrappedValue: Wrapped) {
self.wrappedValue = wrappedValue
}
var projectedValue: String { .init(describing: wrappedValue) }
}
struct Foo {
@CustomStringConversion var number = 5
}
let foo = Foo()
let number: Int = foo.number // 5
let stringRepresentation: String = foo.$number // "5"
But as @LeoDabus pointed out using LosslessStringConvertible
may be better :
struct example<N: Numeric & LosslessStringConvertible>: LosslessStringConvertible {
let number: N
init(number: N) {
self.number = number
}
init?(_ description: String) {
guard let number = N(description) else { return nil }
self.number = number
}
var description: String {
.init(number)
}
}
let bar = example(number: Double.greatestFiniteMagnitude) // 1.7976931348623157e+308
let baz: example<Double>? = example("1.7976931348623157e+308") // 1.7976931348623157e+308
Upvotes: 5
Reputation: 18944
Use generic structure with Numeric protocol.
struct Example<T:Numeric> {
var string: String
init(number: T) {
self.string = "\(number)"
}
}
Upvotes: 2
Reputation: 2024
You can have a look at how swift does this with its String-initializer:
struct Example {
init<Number>(number: Number) where Number: BinaryInteger {
string = String(number)
}
}
Upvotes: -1
Reputation: 29329
struct Example {
var string: String
init(number: Int) {
string = String(number)
}
init(number: Float) {
string = String(number)
}
init(number: Double) {
string = String(number)
}
}
Upvotes: 1