如何在Swift中将字符串用作可打印项

如何在Swift中将字符串用作可打印项,swift,Swift,我正在尝试编写一个函数,该函数接受类型为Printable的参数: func logMessage(message: Printable) { // ... } 奇怪的是,当传入字符串时,这并不像预期的那样工作 这不会编译: logMessage("some string \(someVariable)") // Neither does this: let aString = "aString" logMessage(aString) 然而,本文件汇编了: logMessage(

我正在尝试编写一个函数,该函数接受类型为Printable的参数:

func logMessage(message: Printable) {
    // ...
}
奇怪的是,当传入字符串时,这并不像预期的那样工作

这不会编译:

logMessage("some string \(someVariable)")

// Neither does this:
let aString = "aString"
logMessage(aString)
然而,本文件汇编了:

logMessage("A string")
// This works too:
let aString: Printable = "a string"
logMessage(aString)
let aString: Printable = "Ceci n'est pas une String"
这很令人困惑。似乎在某些情况下字符串实现了可打印,而在另一些情况下不是

此外,字符串插值似乎总是生成一个不实现可打印的字符串。此操作在运行时崩溃,并出现强制转换错误:

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

你知道这是怎么回事吗?

你是对的,
String
不符合
Printable
。其原因如下:

logMessage("A string")
// This works too:
let aString: Printable = "a string"
logMessage(aString)
let aString: Printable = "Ceci n'est pas une String"
您不是在用该文本创建一个
字符串
,而是在创建一个
NSString
(它是
可打印的

通常,在Swift中,编写受协议约束的通用函数通常更好。所以不是

func logMessage(message: Printable) {
    // ...
}
你最好写下:

func logMessage<T: Printable>(message: T) {
    // ...
}
这将适用于
字符串
,实际上也适用于任何不可
打印的
(尽管您将得到一个涉及损坏的类名的毫无帮助的输出)

或者,您可以使用
Streamable
哪些字符串符合:

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

let s: String = "hello"
logMessage(s)
func日志消息(消息:T){
println(消息)
}
让我们:String=“你好”
日志信息

我想我在twitter上读到过一段时间,Swift团队的一位成员提到,
String
不符合
Printable
的原因正是因为他们不希望人们像这样直接使用
Printable
,最好总是使用
toString
或类似的东西在此注释中,它的行为正确:“没有理由将Printable用作类型或泛型约束。println()和toString()可用于任何类型,应该使用它而不是访问“description”属性。”@NateCook是的,我个人认为可以指定类型需要提供正确格式的描述,而不是作为函数signatureKind的一部分的损坏的类型名,因为该字符串不能实现可打印。我想第三种解决方案是在字符串扩展中实现可打印。@MihaiDamian我同意这是意外的,但本质上苹果说的是编写
函数,而不是
,并使用
toString()
无论您在何处使用了
description
属性。因此我很好奇:如果我甚至没有为参数使用协议,为什么logMessage(message:T)比logMessage(message:Any)更好。它只是为了帮助编译器进行优化,因为类型将在编译时确定吗?