How to use strings as printable stuff in Swift

I am trying to write a function that takes a parameter of type Printable:

func logMessage(message: Printable) {
    // ...
}

      

Strange, it doesn't work as expected when passed in Strings.

This won't compile:

logMessage("some string \(someVariable)")

// Neither does this:
let aString = "aString"
logMessage(aString)

      

This, however, compiles:

logMessage("A string")
// This works too:
let aString: Printable = "a string"
logMessage(aString)

      

It's pretty confusing. It seems that in some cases String implements Printable and in others it does not.

Also, it seems that string-interpolation always produces a string that doesn't implement Printable. This leads to runtime crashes with a cast error:

let aString = "a string"
let interpolatedString = "contains \(aString)"

      

Any idea what's going on here?

+3


source to share


1 answer


You are right that String

does not correspond Printable

. The reason this compiles is:

let aString: Printable = "Ceci n'est pas une String"

      

is that you don't create String

with that literal - you create NSString

(which Printable

).

As a general rule, in Swift it is usually better to write general protocol-limited functions. Therefore, instead of

func logMessage(message: Printable) {
    // ...
}

      

you are probably better off writing:

func logMessage<T: Printable>(message: T) {
    // ...
}

      



This approach has several advantages: better security type and style erasure prevention, better performance, etc. You can read more about this stuff here .

But you will still run into a problem because you cannot get through String

. You have two options. First, just don't limit it at all:

func logMessage<T>(message: T) {
    // ...then use toString(message) to create a String if you need one,
    // or use string interpolation or print()
}

      

This will work with String

, and in fact will work with anyone that isnt Printable

(although you will end up with completely useless output associated with a malformed class name).

Or you can use Streamable

whose lines match:

func logMessage<T: Streamable>(message: T) {
    println(message)
}

let s: String = "hello"
logMessage(s)

      

I think I have been reading on twitter for a while, one of the Swift teams mentions that the reason is String

not consistent Printable

, precisely because they didn't want people using Printable

, just like that, it's better to always use it toString

or similar.

+3


source







All Articles