协议功能实现,实际上不符合协议

Protocol function implementation without actually conforming to a protocol

我是初学者 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 实现而不符合协议,为什么会出错?我的意思是,这个协议只是简单地说“嘿,你需要实现 var description: String 因为你符合我的要求,但为什么我们不能在不符合协议的情况下实现 var description: String

是不是因为在后台,有一个函数或某种类型通过一些代码接收类型 CustomStringConvertible 和 运行,瞧!文本出现。

CustomStringConvertible 允许您执行 print(linkedListInstance) 将描述 setter.

返回的任何内容打印到控制台

您可以在此处找到有关此协议的更多信息:https://developer.apple.com/reference/swift/customstringconvertible

为什么不遵守协议就不能实现var description: String

比较:

class Foo {
    var description: String { return "my awesome description" }
}

let foo = Foo()

print("\(foo)") // return "Whosebug.Foo" (myBundleName.Foo)

class Foo: CustomStringConvertible {
    var description: String { return "my awesome description" }
}

let foo = Foo()

print("\(foo)") // return "my awesome description"

当你使用CustomStringConvertible时,你保证这个class有变量description,然后,你可以调用它,而无需知道其他实现细节。

另一个例子:

(someObject as? CustomStringConvertible).description

我不知道 someObject 的类型,但是,如果它订阅了 CustomStringConvertible,那么,我可以调用 description

如果您希望字符串插值使用您的description,您必须符合CustomStringConvertible。属性。

您在 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_unlockeddefined 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)
}

请注意,如果对象符合 CustomStringConvertible.

,则 _print_unlocked 仅调用对象的 description 方法

如果您的对象不符合 CustomStringConvertible_print_unlocked 中使用的其他协议之一,则 _print_unlocked 会为您的对象创建一个 Mirror,这最终只打印对象的类型(例如 MyProject.LinkedList),仅此而已。