如何在 Swift 中正确声明一个变量?
How properly declare a variable in Swift?
我发现这些在 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 声明了一个 let,我们知道区别;但是为什么 Swift 允许方法 4?
这四种方法有什么区别?
我特别困惑方法 2 和方法 4。此外,为什么方法 3 与方法 4 相比失去了最后的括号?
方法一很明显。
在方法 2 中,您所做的是为给定变量定义一个 getter。
方法 3 中的 dogName 类型是 () -> String
而不是 String
。你在那里初始化的是一个命名的 lambda。
在方法 4 中,您使用 returns 字符串的匿名(未命名)lambda 函数初始化变量。
3 和 4 之间的区别在于,在 4th 中你用 () 调用该函数所以你得到 String 而在之前你没有,所以它是一个函数。
我设置了一个快速测试,将所有内容重命名为 dogName1
、dogName2
、dogName3
和 dogName4
。然后我添加了代码以尝试将每个名称更改为 "Snoopy".
#2 和#3 没有构建,因为编译器知道它们都是只读的。 (#2,尽管被声明为 var
,但始终设置为 return "Charlie"。
在注释掉这两行之后,我设置了两个断点 - 在初始化后打开,一个在尝试更新后设置。
最后我尝试对每一个都做 print
。
断点 #1:#1 和 #4 设置为 "Charlie",#2 不存在(因为它未初始化)和 #3显示为已初始化但没有值(因为尚未调用它。是的,最后的 ()
初始化内存中的某些内容。
断点 #2: #1 和 #4 更新为 "Snoopy".
print
的结果:#1 和#4 是 "Snoopy",#2 是 "Charlie",#3 是“(函数)".
结论:#1和#4没有区别。每个都被声明为 var
并且默认值为 "Charlie"。 #2,由于 let
是只读的,并且将始终 return "Charlie"。 #3?它会创建一个实例,如果您尝试更改它,它不会构建 - 但我不知道如何使用它。
如果有人对#3 有更多补充,我会更新这个答案。
方法 1 是 String 的标准变量声明。它有一个 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
}()
为了理解差异,让我们使用一个更具描述性的例子
这是一个classFoo
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()
方法一是存储属性className
与setter和getter
let name = foo.className
foo.className = "Bar"
print(foo.className) // "Bar"
方法 2 是计算出来的 属性 dogName1
只有一个 getter。它可用于动态计算值。
print(foo.dogName1) // "Charlie Bar"
方法三是() -> String
类型的闭包dogName2
。可以赋值给一个变量,稍后执行
let dogName = foo.dogName2 // assigns the closure but does not return the string.
print(dogName()) // "My name is Charlie"
方法4是变量dogName3
当一个实例once立即执行它的关闭[= =23=]被初始化(由print
行证明)
print(foo.dogName3) // "My name is Charlie" but does not execute the closure and print `string` again
甚至还有一个方法5:如果你声明dogName3
为lazy
lazy var dogName3 : String = {
直到第一次访问变量时才执行闭包。优点是你甚至可以在闭包中使用 self
这在 方法 4.
中是不可能的
我发现这些在 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 声明了一个 let,我们知道区别;但是为什么 Swift 允许方法 4?
这四种方法有什么区别?
我特别困惑方法 2 和方法 4。此外,为什么方法 3 与方法 4 相比失去了最后的括号?
方法一很明显。
在方法 2 中,您所做的是为给定变量定义一个 getter。
方法 3 中的 dogName 类型是 () -> String
而不是 String
。你在那里初始化的是一个命名的 lambda。
在方法 4 中,您使用 returns 字符串的匿名(未命名)lambda 函数初始化变量。
3 和 4 之间的区别在于,在 4th 中你用 () 调用该函数所以你得到 String 而在之前你没有,所以它是一个函数。
我设置了一个快速测试,将所有内容重命名为 dogName1
、dogName2
、dogName3
和 dogName4
。然后我添加了代码以尝试将每个名称更改为 "Snoopy".
#2 和#3 没有构建,因为编译器知道它们都是只读的。 (#2,尽管被声明为 var
,但始终设置为 return "Charlie"。
在注释掉这两行之后,我设置了两个断点 - 在初始化后打开,一个在尝试更新后设置。
最后我尝试对每一个都做 print
。
断点 #1:#1 和 #4 设置为 "Charlie",#2 不存在(因为它未初始化)和 #3显示为已初始化但没有值(因为尚未调用它。是的,最后的 ()
初始化内存中的某些内容。
断点 #2: #1 和 #4 更新为 "Snoopy".
print
的结果:#1 和#4 是 "Snoopy",#2 是 "Charlie",#3 是“(函数)".
结论:#1和#4没有区别。每个都被声明为 var
并且默认值为 "Charlie"。 #2,由于 let
是只读的,并且将始终 return "Charlie"。 #3?它会创建一个实例,如果您尝试更改它,它不会构建 - 但我不知道如何使用它。
如果有人对#3 有更多补充,我会更新这个答案。
方法 1 是 String 的标准变量声明。它有一个 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
}()
为了理解差异,让我们使用一个更具描述性的例子
这是一个classFoo
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()
方法一是存储属性
className
与setter和getterlet name = foo.className foo.className = "Bar" print(foo.className) // "Bar"
方法 2 是计算出来的 属性
dogName1
只有一个 getter。它可用于动态计算值。print(foo.dogName1) // "Charlie Bar"
方法三是
() -> String
类型的闭包dogName2
。可以赋值给一个变量,稍后执行let dogName = foo.dogName2 // assigns the closure but does not return the string. print(dogName()) // "My name is Charlie"
方法4是变量
dogName3
当一个实例once立即执行它的关闭[= =23=]被初始化(由print
行证明)print(foo.dogName3) // "My name is Charlie" but does not execute the closure and print `string` again
甚至还有一个方法5:如果你声明
dogName3
为lazy
lazy var dogName3 : String = {
直到第一次访问变量时才执行闭包。优点是你甚至可以在闭包中使用
self
这在 方法 4. 中是不可能的