如何正确地在Swift中声明变量?
我发现在Swift中声明变量的这些不同方法非常有趣:如何正确地在Swift中声明变量?,swift,swift3,var,variable-declaration,let,Swift,Swift3,Var,Variable Declaration,Let,我发现在Swift中声明变量的这些不同方法非常有趣: // METHOD 1 var dogName: String = "Charlie" // METHOD 2 var dogName: String { return "Charlie" } // METHOD 3 let dogName = { return "Charlie" } // METHOD 4 var dogName: String = { return "Charlie" }() 显然,方法3
// METHOD 1
var dogName: String = "Charlie"
// METHOD 2
var dogName: String {
return "Charlie"
}
// METHOD 3
let dogName = {
return "Charlie"
}
// METHOD 4
var dogName: String = {
return "Charlie"
}()
显然,方法3声明了一个let,我们知道了其中的区别;但是为什么Swift允许方法4
这四种方法的区别是什么?
我特别混淆了方法2和方法4。此外,为什么方法3与方法4相比失去了最后的括号?方法1非常明显 在方法2中,您所做的是为给定变量定义一个getter 方法3中的狗名类型是
()->字符串
,而不是字符串
。你初始化的是一个名为lambda的
在方法4中,使用返回字符串的匿名(未命名)lambda函数初始化变量
3和4之间的区别在于,在第4节中,你用()调用该函数,这样你就得到了字符串,而在上一节中,你不这样做,所以它是一个函数。我设置了一个快速测试,将所有内容重命名为
dogName1
,dogName2
,dogName3
和dogName4
。然后我添加了代码,试图将每个名称更改为“Snoopy”
let dogName = {
return "Charlie"
}
print(dogName) -> "(Function)"
print(dogName()) -> "Charlie"
dogName = "Rex" // Invalid as property is read-only
#2和#3没有生成,因为编译器知道它们都是只读的。(#2,尽管被声明为var
,但设置为始终返回“Charlie”
在注释掉这两行之后,我设置了两个断点——在初始化之后打开,在尝试更新之后打开
最后,我试着把每一张都打印出来
断点#1:断点#1和#4被设置为“Charlie”,断点#2不在那里(因为它没有初始化),断点#3显示为已初始化,但没有值(因为它还没有被调用。是的,()
最后初始化了内存中的某些内容
断点#2:断点#1和#4已更新为“史努比”
打印结果:#1和#4为“史努比”,#2为“查理”,而#3为“功能”
结论:第1个和第4个之间没有区别。每一个都声明为var
,默认值为“Charlie”。#2是只读的,因为let
,并且总是返回“Charlie”。#3?它会创建一个实例,如果您试图更改它,它不会生成-但我不知道如何使用它
如果有人对#3有更多的补充,我会更新这个答案。方法1是字符串的标准变量声明。它有一个setter和一个getter
var dogName: String = "Charlie"
print(dogName) -> "Charlie"
dogName = "Rex" // Valid
方法2是字符串类型的计算属性,是只读的
var dogName: String {
return "Charlie"
}
print(dogName) -> "Charlie"
dogName = "Rex" // Invalid as property is read-only
方法3是类型为()->String的只读属性,因此基本上是一个lambda函数
let dogName = {
return "Charlie"
}
print(dogName) -> "(Function)"
print(dogName()) -> "Charlie"
dogName = "Rex" // Invalid as property is read-only
方法4是初始化包含对象时将执行的闭包。由于它是var
,因此可以用另一个值替换它
var dogName: String = {
return "Charlie"
}()
print(dogName) -> "Charlie"
dogName = "Rex" // Valid
也就是说,由于方法4是一个闭包,您可以在其中执行其他命令。下面是一个示例,您可以使用此构造初始化UILabel:
var dogNameLabel: UILabel = {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
label.text = "Charlie"
return label
}()
为了理解差异,让我们使用一个更具描述性的示例 这是一个类
Foo
class Foo {
var className = "Foo"
var dogName1 : String { return "Charlie " + className }
let dogName2 = {
return "My name is Charlie"
}
var dogName3 : String = {
var string = "My"
string += " name"
string += " is"
string += " Charlie"
print(string)
return string
}()
}
现在让我们创建一个实例
let foo = Foo()
- 方法1是带有setter和getter的存储属性
className
let name = foo.className foo.className = "Bar" print(foo.className) // "Bar"
- 方法2是仅带有getter的计算属性
。它可用于动态计算值dogName1
print(foo.dogName1) // "Charlie Bar"
- 方法3是类型为
的闭包()->String
。它可以分配给变量,然后执行dogName2
let dogName = foo.dogName2 // assigns the closure but does not return the string. print(dogName()) // "My name is Charlie"
- 方法4是变量
,当初始化实例dogName3
时,该变量立即执行其闭包一次(由Foo()
行证明)print
- 甚至还有一个方法5:如果您将
声明为dogName3
lazy
直到第一次访问变量时才会执行闭包。优点是您甚至可以在闭包中使用lazy var dogName3 : String = {
,这在方法4中是不可能的self
get
和set
,使其可读写。但是,当如上所示声明时,它们隐式地只有一个getter,这实际上使它们是只读的。请参阅@ITAFERBER Yes您是对的,一个计算属性并不总是只读的,谢谢您指出这一点。我删除了Method2描述中的错误部分。@Sulthan这不是真的。Method 3是一个lambda,您需要调用它来获取值。您可以用let x={return 5};print(type(of:x))