I need to convert an Integer
value to String
. I made a variable with an Integer
value and then I have printed that using print
. What is the different between the below approaches?
var word = "Count is "
var count = 100
print(word+String(describing: count)); // Count is 100
print(word+String(count)); // Count is 100
Your question is actually unnecessary because if all you want to do here is print, you can just do it directly:
print("Count is", count) // Count is 100
That's because print
takes a variadic parameter and inserts space as the default separator.
However, let's answer the question anyway.
It's the difference between coercion and representation.
Coercion. Certain types can be changed into certain other types. You can change a Double to an Int and an Int to a Double. You can change an Int to a String and a String (maybe) to an Int. This is possible because the second type has an initializer whose parameter is the first type. This is something you would do in your actual program, like this:
let sum : Int = x + y
self.myLabel.text = "Your total is \(String(sum))"
Representation. For debugging purposes, all types can benefit from being representable as a string. Suppose you have a Person type. You can't change a Person to a String and vice versa — that makes no sense — but you would surely like to be able to print
a Person to the console to see if you are getting the right results. This is possible because the Person type itself supplies a printable description. This is something you would do for debugging purposes:
let p = Person(first:"Matt", last:"Neuburg")
print("p is \(String(describing:p))")
Comment 1. This distinction is fairly new in Swift. It used to be that String(...)
was used to express both notions. But the powers that be realized that that was a confusing conflation of the two distinct mechanisms. So nowadays, an attempt to write String(p)
will fail, whereas earlier it would have succeeded. String has no Person initializer, so String(p)
is forbidden; you now have to say explicitly that you are describing, not coercing.
Comment 2. The need to print a description is so obviously common that you do not have to pass thru String(describing:)
if all you want to do is log the object itself. You can write print(p)
, because this is a shorthand for print(String(describing:p))
. Similarly, string interpolation calls String(describing:)
for you, so you can write print("p is \(p)")
. And, as I said at the outset, print
takes a variadic parameter and inserts space as the default separator, so you can write print("p is", p)
.
Reading the docs might help!
Here's an excerpt from String.init(describing:)
Use this initializer to convert an instance of any type to its preferred representation as a String instance. The initializer creates the string representation of
instance
in one of the following ways, depending on its protocol conformance:
- If instance conforms to the
TextOutputStreamable
protocol, the result is obtained by callinginstance.write(to: s)
on an empty string s.- If instance conforms to the
CustomStringConvertible
protocol, the result isinstance.description
.- If instance conforms to the
CustomDebugStringConvertible
protocol, the result isinstance.debugDescription
.- An unspecified result is supplied automatically by the Swift standard library.
Int
conforms to CustomStringConvertible
, so String(describing: someInt)
is the same as someInt.description
.
Now let's look at String(someInt)
, this calls this initializer:
public init<T>(_ value: T) where T : LosslessStringConvertible
Int
also conforms to LosslessStringConvertible
. In fact, LosslessStringConvertible
inherits from CustomStringConvertible
. LosslessStringConvertible
specifies only one requirement - an initializer that takes a string.
The docs for init<T>(_:)
says this:
Creates an instance from the description of a given
LosslessStringConvertible
instance.
Even though description
is not in a monospace font, I am quite sure (though not 100%) that this refers to the description
property of CustomStringConvertible
.
Assuming that init<T>(_:)
indeed returns the description
, String(describing: someInt)
always returns the same value as String(someInt)
.
Note that this does not hold true for all types. It only holds true for types that conforms to LosslessStringConvertible
but not TextOutputStreamable
. If you have a type that conforms to both, results can be different:
struct A: TextOutputStreamable, LosslessStringConvertible {
init?(_ description: String) { }
init() { }
var description: String {
return "foo"
}
func write<Target>(to target: inout Target) where Target : TextOutputStream {
target.write("bar")
}
}
String(describing: A()) // bar
String(A()) // foo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With