Swift中大写的"Self"和小写的"self"有何区别

81
在玩 Swift Playground 时,我注意到除了小写的 self,还有一个大写的 Self。它们之间有什么区别吗?如果有,这两个关键字的用法是什么,特别是 Self 的用法?

1
在协议扩展中,关于selfSelf的值有相当多的细微差别 - 我在这个问答中详细讨论了这个问题。 - Hamish
7个回答

85

3
我今天情绪不好,很挑剔、吹毛求疵。但别担心!我抽出时间来告诉你:为了完整地回答问题,这个答案应该明确指出 self 大体上是 Objective-C 开发者所认为的那样。对于结构体、枚举等的讨论可能是不必要的绕路。 - Tommy
请参阅语言参考中的“协议关联类型声明”:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html - Rob Napier
12
在2015年苹果全球开发者大会的视频《面向协议的编程》中,详细介绍了这个概念。视频链接为:https://developer.apple.com/videos/wwdc/2015/?id=408 ,可以跳至16分05秒处,找到关于“Self类型”的具体讲解。请注意,本翻译不对内容进行解释或添加任何额外信息。 - Sez

13

Self也可以在类中使用,非常有用。这篇文章介绍了相关内容。

以下是一个示例。你有一个名为MyClass的类。MyClass类有返回实例的方法。现在你添加了一个名为MySubclassMyClass子类。你想让这些方法返回MySubclass的实例而不是MyClass的实例。下面的代码展示了如何实现。注意这些方法既可以是实例方法也可以是类方法。

class MyClass: CustomStringConvertible {

    let text: String

    // Use required to ensure subclasses also have this init method
    required init(text: String) {
        self.text = text
    }

    class func create() -> Self {
        return self.init(text: "Created")
    }

    func modify() -> Self {
        return type(of: self).init(text: "modifid: " + text)
    }

    var description: String {
        return text
    }

}

class MySubclass: MyClass {
    required init(text: String) {
        super.init(text: "MySubclass " + text)
    }
}

let myClass = MyClass.create()
let myClassModified = myClass.modify()

let mySubclass = MySubclass.create()
let mySubclassModified = mySubclass.modify()

print(myClass)
print(myClassModified)
print(mySubclass)
print(mySubclassModified)
下一行打印出:
// Created
// modifid: Created
// MySubclass Created
// MySubclass modifid: MySubclass Created

9

在协议和扩展声明中使用Self而不是self

extension protocolName where Self: UIView 
{
  func someFunction()
  {
    self.layer.shadowColor = UIColor.red.cgColor
  }
}

在我看来,这里的 whereSelf 的一个很好的例子。 - thedp

7

我认为这个问题需要一个更简单的答案,更侧重于Selfself之间的区别,并且可能面向刚接触Swift的人。

self - 显式引用当前类型或其所在实例的类型。

class MyClass {
  func showClass() {
       print("\(self)")
    }
  }
let someClass = MyClass()
someClass.showClass()
// prints "MyClass"

Self - 用于 protocolextension 声明中,特指将符合该协议的最终类型。

protocol MyProtocol {
   static func returnSelf() -> Self
}

class MyClass: MyProtocol {
   // define class
}

MyClass.returnSelf() 
// returns MyClass

区别在于self在类型和类型实例中使用,用于引用所在的类型;而Self在协议和扩展中使用,其中实际的type尚未知晓。
更简单地说,在现有类型内部使用self;而使用Self来引用Self尚不存在的类型。
阅读更多请点击这里:

3

self - 指代类的实例或对象。

  class SampleClassOne {
    let name: String
    init(name: String) {
        self.name = name
    }
}

自指(Self)- 指协议或扩展的类型。
    class SampleClassTwo {
    static let name: String = "Hello"
    private func printName() {
        print("\(Self.name)")
    }
}

protocol SampleProtocol {
    func sampleFunc() -> Self
}

下面是一个简单的例子,让我们一起了解。

 extension Int {
    var add: Self { //refer to the Type
        return self + 100 //refer to the instance
    }
}
print(5.add)

3
我理解Self是一个类型名称(例如类名),而self是类/结构体的实例,例如:
struct Person {
     static var documentNumner = "9484930"
     var name: String
     var computedFullName: String {
        return ("\(self.name) with document number: \(Self.documentNumner)")

    }
}

您不能在静态属性中使用self,但是可以使用Self。


1

在协议扩展方法体中,Self也可以用作返回类型,它将返回确认类型实例,并用于使用"as"进行类型转换。请参见下面的示例:

extension <Protocol-Name> where Self:<Class-Name> {
static func foo(_ param:Type)-> Self{
    guard let abc = method() as? Self else{
        return xyz
    }
}}

简而言之,Self 可以用来指代符合协议的类型。

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