我是初学Swift学习者,我对协议有疑问。我已经按照教程教你链接列表,如下所示:
节点:
class LinkedListNode<Key> {
let key: Key
var next: LinkedListNode?
weak var previous: LinkedListNode?
init (key: Key) {
self.key = key
}
}
链表:
class LinkedList<Element>: CustomStringConvertible {
typealias Node = LinkedListNode<Element>
private var head: Node?
// irrelevant code removed here
var description: String {
var output = "["
var node = head
while node != nil {
output += "\(node!.key)"
node = node!.next
if node != nil { output += ", " }
}
return output + "]"
}
}
var description: String
实现只允许您打印链表中的每个元素。
到目前为止,我了解链表的结构,我的问题实际上并不是关于链表。我不明白的是协议CustomStringConvertible
。如果我只有var description: String
实施而不符合协议,为什么会出错呢?我的意思是,这个协议只是简单地说&#34;嘿,你需要实现var description: String
,因为你符合我,但为什么我们不能实现var description: String
而不符合协议?
是不是因为在后台,有一个函数或某种类型接受CustomStringConvertible
类型并通过一些代码运行它瞧!文字出现。
答案 0 :(得分:1)
为什么我们不能在不符合协议的情况下实施var description: String
?
比较
class Foo {
var description: String { return "my awesome description" }
}
let foo = Foo()
print("\(foo)") // return "stackoverflow.Foo" (myBundleName.Foo)
和
class Foo: CustomStringConvertible {
var description: String { return "my awesome description" }
}
let foo = Foo()
print("\(foo)") // return "my awesome description"
当您使用CustomStringConvertible
时,您保证此类具有变量description
,然后,您可以调用它,而无需了解其他实现细节。
另一个例子:
(someObject as? CustomStringConvertible).description
我不知道someObject的类型,但是,如果它订阅了CustomStringConvertible
,那么我可以调用description
。
答案 1 :(得分:1)
如果您希望字符串插值使用CustomStringConvertible
属性,则必须符合description
。
你在Swift中使用字符串插值,如下所示:
"Here's my linked list: \(linkedList)"
编译器基本上将其转换为:
String(stringInterpolation:
String(stringInterpolationSegment: "Here's my linked list: "),
String(stringInterpolationSegment: linkedList),
String(stringInterpolationSegment: ""))
String(stringInterpolationSegment:)
defined like this的通用版本:
public init<T>(stringInterpolationSegment expr: T) {
self = String(describing: expr)
}
String(describing: )
是defined like this:
public init<Subject>(describing instance: Subject) {
self.init()
_print_unlocked(instance, &self)
}
_print_unlocked
是defined like this:
internal func _print_unlocked<T, TargetStream : TextOutputStream>(
_ value: T, _ target: inout TargetStream
) {
// Optional has no representation suitable for display; therefore,
// values of optional type should be printed as a debug
// string. Check for Optional first, before checking protocol
// conformance below, because an Optional value is convertible to a
// protocol if its wrapped type conforms to that protocol.
if _isOptional(type(of: value)) {
let debugPrintable = value as! CustomDebugStringConvertible
debugPrintable.debugDescription.write(to: &target)
return
}
if case let streamableObject as TextOutputStreamable = value {
streamableObject.write(to: &target)
return
}
if case let printableObject as CustomStringConvertible = value {
printableObject.description.write(to: &target)
return
}
if case let debugPrintableObject as CustomDebugStringConvertible = value {
debugPrintableObject.debugDescription.write(to: &target)
return
}
let mirror = Mirror(reflecting: value)
_adHocPrint_unlocked(value, mirror, &target, isDebugPrint: false)
}
请注意,如果对象符合_print_unlocked
,则description
仅调用对象的CustomStringConvertible
方法。
如果您的对象不符合CustomStringConvertible
或_print_unlocked
中使用的其他协议之一,那么_print_unlocked
会为您的对象创建Mirror
,最终只打印对象的类型(例如MyProject.LinkedList
)而不打印任何其他内容。
答案 2 :(得分:-1)
CustomStringConvertible
允许您执行print(linkedListInstance)
,它将在控制台上打印描述设置器返回的内容。
您可以在此处找到有关此协议的更多信息:https://developer.apple.com/reference/swift/customstringconvertible