协议扩展中的 'where self' 是什么?

47

我看到很多以下格式的例子:

extension Protocolname where Self: UIViewController

where Self 在协议扩展中是什么?我找不到相关文档。

3个回答

71
那个语法是:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID521 考虑一下:
protocol Meh {
    func doSomething()
}

// Extend protocol Meh, where `Self` is of type `UIViewController`
// func blah() will only exist for classes that inherit `UIViewController`. 
// In fact, this entire extension only exists for `UIViewController` subclasses.

extension Meh where Self: UIViewController {
    func blah() {
        print("Blah")
    }

    func foo() {
        print("Foo")
    }
}

class Foo : UIViewController, Meh { //This compiles and since Foo is a `UIViewController` subclass, it has access to all of `Meh` extension functions and `Meh` itself. IE: `doSomething, blah, foo`.
    func doSomething() {
        print("Do Something")
    }
}

class Obj : NSObject, Meh { //While this compiles, it won't have access to any of `Meh` extension functions. It only has access to `Meh.doSomething()`.
    func doSomething() {
        print("Do Something")
    }
}

以下代码会出现编译错误,因为Obj没有访问Meh扩展函数的权限。
let i = Obj()
i.blah()

但以下方法可以正常工作。
let j = Foo()
j.blah()

换句话说,Meh.blah() 只对 UIViewController 类型的类可用。

为什么人们会在protocol Mehextension Meh where Self: UIViewController中使用相同的名称Meh,这对我来说似乎很令人困惑。 - Felix
2
@Felix;因为该扩展实际上是在协议上的扩展,而不是在类本身上的扩展...但只有当UIViewController实现它时。 - Brandon
如果我想编写一个通用的Meh()和一个只在它是ViewController对象时才执行的Meh(),该怎么办? - Oscar

5

下面是一个示例,解释了where self: UIViewController的用途:

protocol SBIdentifiable {
    static var sbIdentifier: String { get }
}

extension SBIdentifiable where Self: UIViewController {
    static var sbIdentifier: String {
        return String(describing: self)
    }
}

extension UIVieWcontroller: SBIdentifiable { }

class ViewController: UIViewController {
  func loadView() {
  /*Below line we are using the sbIdentifier which will return the 
   ViewController class name.
    and same name we would mentioned inside ViewController 
    storyboard ID. So that we do not need to write the identifier everytime. 
   So here where Self: UIViewController means it will only conform the protocol of type UIViewController*/ 

  let viewController = self.instantiateViewController(withIdentifier: 
    self.sbIdentifier) as? SomeBiewController
  }
}

5

您可以在这里找到相同的示例: WWDC2015-408,(强烈建议观看它,因为它说明了原因)

此外,另一个类似的示例是使用泛型where子句的扩展

struct Stack<Element> {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}

where子句会对扩展进行限制,因此只有当堆栈中的项目可比较时,扩展才会添加isTop(_:)方法。

extension Stack where Element: Equatable {
    func isTop(_ item: Element) -> Bool {
        guard let topItem = items.last else {
            return false
        }
        return topItem == item
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接