String(描述为Int)与String(Int)之间有什么区别?

Sen*_*ake 4 swift

我需要将Integer值转换为String。我用一个Integer值创建了一个变量,然后使用进行了打印print。以下方法之间有什么区别?

var word = "Count is "
var count = 100

print(word+String(describing: count)); // Count is 100

print(word+String(count)); // Count is 100
Run Code Online (Sandbox Code Playgroud)

Swe*_*per 7

阅读文档可能会有所帮助!

这是摘录自 String.init(describing:)

使用此初始值设定项将任何类型的实例转换为其首选表示形式为 String 实例。初始instance值设定项以下列方式之一创建字符串表示,具体取决于其协议一致性:

  • 如果实例符合TextOutputStreamable协议,则通过调用instance.write(to: s)空字符串 s获得结果。
  • 如果实例符合CustomStringConvertible协议,则结果为instance.description
  • 如果实例符合CustomDebugStringConvertible协议,则结果为instance.debugDescription
  • Swift 标准库会自动提供未指定的结果。

Int符合CustomStringConvertible,因此String(describing: someInt)与 相同someInt.description

现在让我们看看String(someInt),它调用了这个初始化器:

public init<T>(_ value: T) where T : LosslessStringConvertible
Run Code Online (Sandbox Code Playgroud)

Int也符合LosslessStringConvertible. 事实上,LosslessStringConvertible继承自CustomStringConvertible. LosslessStringConvertible仅指定一个要求 - 一个接受字符串的初始化程序。

文档是这样init<T>(_:)说的:

根据给定LosslessStringConvertible实例的描述创建一个实例。

即使description不是等宽字体,我敢肯定(虽然不是100%),这指description的财产CustomStringConvertible

假设init<T>(_:)确实返回description,则String(describing: someInt)始终返回与 相同的值String(someInt)

请注意,这并不适用于所有类型。它仅适用于符合LosslessStringConvertible但不符合 的类型TextOutputStreamable。如果您的类型同时符合两者,结果可能会有所不同:

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
Run Code Online (Sandbox Code Playgroud)


mat*_*att 6

你的问题其实是不必要的,因为如果所有你想要做的,是打印,你可以直接做到这一点:

print("Count is", count) // Count is 100
Run Code Online (Sandbox Code Playgroud)

那是因为print需要可变参数并插入空格作为默认分隔符。

但是,还是让我们回答这个问题。


回答

这是强制表征之间的区别。

强制性的。某些类型可以更改为某些其他类型。您可以将Double更改为Int,也可以将Int更改为Double。您可以将Int更改为String,并将String(也许)更改为Int。这是可能的,因为第二种类型有一个参数为第一种类型的初始化程序。您可以在实际程序中执行以下操作:

let sum : Int = x + y
self.myLabel.text = "Your total is \(String(sum))"
Run Code Online (Sandbox Code Playgroud)

表示形式。出于调试目的,所有类型都可以从可表示为字符串的形式中受益。假设您有一个Person类型。您不能将Person更改为String,反之亦然-这没有意义-但是您肯定希望能够将printPerson更改为控制台,以查看是否获得正确的结果。这是可能的,因为Person类型本身提供了可打印的描述。您可以出于调试目的执行以下操作

let p = Person(first:"Matt", last:"Neuburg")
print("p is \(String(describing:p))")
Run Code Online (Sandbox Code Playgroud)

评论

评论1。在Swift中,这种区别是相当新的。它曾经String(...)是用来表达这两个概念的。但是人们意识到,这是两种截然不同的机制的混淆。因此,如今,写尝试String(p)将失败,而较早时它将成功。字符串没有人初始值设定项,因此String(p)被禁止;您现在必须明确地说出您正在描述,而不是强迫

评论2。很明显,打印描述很普遍,String(describing:)如果您只想记录对象本身,就不必通过。你可以写print(p),因为这是一个速记print(String(describing:p))。同样,字符串插值会要求String(describing:)您执行操作,因此您可以编写print("p is \(p)")。而且,正如我一开始所说的,print它采用可变参数,并插入空格作为默认分隔符,因此您可以编写print("p is", p)