什么是Swift中使用的"自我"?

Luc*_*ron 37 self ios swift

我是Swift的新手,我想知道用什么self和为什么.

我已经在类和结构中看到了它,但我真的发现它们不是必需的,甚至没有必要在我的代码中提到它们.它们用于什么以及为什么?在什么情况下有必要使用它?

我一直在阅读这个问题的许多问题和答案,但没有一个能完全回答我的问题,而且他们总是倾向于将它与thisJava 相比较,我对此并不熟悉.

Dav*_*mez 60

更新:2015年11月24日

是的,它是同this的JavaselfObjective-C中,但斯威夫特,当你从一个封闭调用属性或方法或区分你的代码(里面的属性名称自只需要初始化).因此,除非您从闭包中进行调用,否则您可以安全地使用几乎所有类组件而不使用self.

"self属性类型的每个实例都有一个名为的隐式属性self,它与实例本身完全等效.您可以使用该self属性在其自己的实例方法中引用当前实例.

increment()上面示例中的方法可能是这样编写的:

func increment() {
    self.count += 1
}
Run Code Online (Sandbox Code Playgroud)

实际上,您不需要self经常编写代码.如果您没有显式写入self,则Swift会假定您在方法中使用已知属性或方法名称时引用当前实例的属性或方法.这个假设通过在Counter的三个实例方法中使用count(而不是self.count)来证明.

当实例方法的参数名称与该实例的属性具有相同名称时,会发生此规则的主要例外.在这种情况下,参数名称优先,并且有必要以更合格的方式引用属性.您可以使用该self属性来区分参数名称和属性名称.

这里,self消除了一个被调用的方法参数x和一个也称为的实例属性之间的歧义x:

摘录自:Apple Inc."The Swift Programming Language(Swift 2 Prerelease)."


这就是Ray Wenderlich建议self在Swift中使用它们的教程:

使用自我

为简明起见,请避免使用self,因为Swift不要求它访问对象的属性或调用其方法.

在需要时使用self来区分初始值设定项中的属性名称和参数,以及在闭包表达式中引用属性时(根据编译器的要求):

class BoardLocation {
  let row: Int, column: Int

  init(row: Int, column: Int) {
    self.row = row
    self.column = column

    let closure = {
      println(self.row)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这是GitHubself对其应用程序的建议:

self在需要时明确引用

访问属性或方法时self,self默认情况下将引用保留为隐式:

private class History {
    var events: [Event]

    func rewrite() {
        events = []
    }
}
Run Code Online (Sandbox Code Playgroud)

仅在语言需要时包含显式关键字 - 例如,在闭包中或参数名称冲突时:

extension History {
    init(events: [Event]) {
        self.events = events
    }

    var whenVictorious: () -> () {
        return {
            self.rewrite()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

理由:这使得自我的捕获语义在闭包中更突出,并避免其他地方的冗长.

  • 关于闭包的注释:如果使用 self 来使代码可读,则可以使属性的使用明确。在 Java 中,出于同样的原因,可以以同样的方式使用“this”。 (3认同)
  • 虽然我非常尊重Ray Wenderlichs团队的工作,但我认为他们不是清洁代码的最佳参考.一般来说,如果代码是本地代码,我建议使用self来乍看之下. (3认同)
  • 当没有隐藏发生时,为什么在关闭时认为有必要? (2认同)

Leo*_*bus 27

在创建扩展时,您还将使用self,例如:

extension Int {
    func square() -> Int {
        return self * self
    }

    // note: when adding mutating in front of it we don't need to specify the return type
    // and instead of "return " whatever
    // we have to use "self = " whatever

    mutating func squareMe() {
        self = self * self
    }
}
let x = 3
let y = x.square()  
println(x)         // 3
printlx(y)         // 9
Run Code Online (Sandbox Code Playgroud)

现在假设您想要更改var结果本身,您必须使用变异函数来进行更改

var z = 3

println(z)  // 3
Run Code Online (Sandbox Code Playgroud)

现在让我们改变它

z.squareMe()

println(z)  // 9
Run Code Online (Sandbox Code Playgroud)

//现在让我们看另一个使用字符串的例子

extension String {
    func x(times:Int) -> String {
        var result = ""
        if times > 0 {
            for index in 1...times{
                result += self
            }
            return result
        }
        return ""
    }

    // note: when adding mutating in front of it we don't need to specify the return type
    // and instead of "return " whatever
    // we have to use "self = " whatever

    mutating func replicateMe(times:Int){
        if times > 1 {
            let myString = self
            for index in 1...times-1{
                self = self + myString
            }
        } else {
            if times != 1 {
                self = ""
            }
        }
    } 
}


var myString1 = "Abc"
let myString2 = myString1.x(2)

println(myString1)         // "Abc"
println(myString2)         // "AbcAbc"
Run Code Online (Sandbox Code Playgroud)

现在让我们改变myString1

myString1.replicateMe(3)

println(myString1)         // "AbcAbcAbc"
Run Code Online (Sandbox Code Playgroud)


mat*_*att 16

在什么情况下有必要使用它

这是必要的,只有当一个局部变量的名称掩盖一个属性的名称使用它.

但是,作为风格(和可读性)的问题,我总是使用它:

  • 我使用它与属性名称,因为否则我想知道这个变量是什么(因为它既不是本地声明也不是传入参数).

  • 我将它用作函数(方法)调用的接收器,以便将这些方法与顶级或本地函数区分开来.

  • 谢谢马特。这些天我感觉“不需要”模式比考虑可读性和良好的风格更重要。恕我直言,风格更重要。 (2认同)

yli*_*x81 10

我要谈谈我们为什么需要self.

当我们定义一个类时,例如:

class MyClass {
    func myMethod()
}
Run Code Online (Sandbox Code Playgroud)

我们正在创建一个类对象.是的,Class也是一个对象.

然后,无论使用该类创建了多少个实例,所有实例都将具有其Class对象的引用点.

您可以想象由Class定义的所有实例方法都在Class对象中,并且它们只有一个副本.

在此输入图像描述

这意味着使用Class创建的所有实例都共享相同的方法.

现在成像您是myMethod类对象,并且因为您为所有实例共享,您必须有办法告诉您正在处理哪个实例.

当有人说instance1.myMethod(),这意味着"嗨!myMethod,请做你的工作,instance1是你正在做的对象".

如何引用调用者发送给您的对象,使用self.

如果我错了,请纠正我,谢谢.

"在实践中,您不需要经常在代码中编写self.如果您没有显式地编写self,那么只要您在方法中使用已知的属性或方法名称,Swift就会假定您引用当前实例的属性或方法."

摘录自:Apple Inc."The Swift Programming Language."iBooks. https://itun.es/tw/jEUH0.l


Nik*_*tin 8

首先:这里已经发布了很好的答案,例子和解释,但我必须指出一些问题:

保留字:self在swift中类似于this 但它与Java或Javascript中的不一样.

正如@Dave Gomez正确引用的那样:

类型的每个实例都有一个名为self的隐式属性,它与实例本身完全等效.

这里开始了一个主要的区别,因为:

  1. 迅速(至少现在)的"每一个实例"几乎是每件事
  2. 在Java中(例如)你只能this在实例范围内使用word ,在swift中你几乎可以在每个地方使用它

这里举几个例子:

//Example 1:
var x="foo"
x.self="bar".self//compiles and run

//Example 2:
print.self(x);//compiles and run

//Example 3:
func myOther(self otherSelf:Person){}
myOther(self: personObject);//compiles and run

//Example 4:
class Foo{
      var bar=""
      init(){
          self.addSome()//this would be the same in Java
      }
      func addSome(){
          //But definitely not this:
          self.self.bar.self.self="some".self.self
      }
}
//Guess what - also compiles and run...
let f=Foo()
print(f.bar)
Run Code Online (Sandbox Code Playgroud)

如果你想阅读更多内容,请参阅:为什么'self.self'编译并快速运行

OP问题是关于swift的内容,所以我不会向读者解释它在Java或Javascript中的含义(但如果有些读者需要它只是写评论).