据我所知,Swift是一种编译型语言,但它在编译时不检查类型。这使我感到困惑。编译器如何知道类型错误?如果编译器不检查类型,那么在生产环境中岂不是有问题?
当我尝试给一个“let”赋值时,会出现以下错误提示:
“Cannot assign to property: 'variableName' is a 'let' constant Change 'let' to 'var' to make it mutable”。
let
关键字定义一个常量:
let theAnswer = 42
theAnswer
不能在之后更改。这就是为什么任何使用 let
写的 weak
都不行。它们需要在运行时更改,因此必须使用 var
。
var
定义一个普通变量。
有趣的是:
常量的值不需要在编译时知道,但必须精确地分配一次值。
另一个奇怪的特点是:
您可以使用几乎任何字符作为常量和变量名称,包括 Unicode 字符:
let = "dogcow"
摘自:苹果公司《Swift编程语言》iBooks. https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=881256329
由于评论请求添加其他事实到答案中,因此将其转换为社区知识库答案。请随意编辑答案以使其更好。
auto = "dogcow";
是有效的。 - bames53if === { = ♠︎ }
:) ;) - clt60let
是不可变的,一旦初始化就不能再改变,我看到每个人都在他们的例子中使用 integers
。试着用 let 前缀取一个 NSMutableArray
,你仍然可以从中 添加和删除 对象。正确的是 let 使一个 const 指针,所以我们不能再次初始化对象,但我们可以通过添加或追加来改变它的值。 - TheTigervar
和let
都是引用,因此let
是一个常量引用。使用基本类型并不能真正显示出let
与const
的区别。区别在于将其与类实例(引用类型)一起使用时:class CTest
{
var str : String = ""
}
let letTest = CTest()
letTest.str = "test" // OK
letTest.str = "another test" // Still OK
//letTest = CTest() // Error
var varTest1 = CTest()
var varTest2 = CTest()
var varTest3 = CTest()
varTest1.str = "var 1"
varTest2.str = "var 2"
varTest3 = varTest1
varTest1.str = "var 3"
varTest3.str // "var 3"
var
和let
与所绑定标识符是否引用无关。如果类型是“结构体”类型,则在概念上是一个值。如果类型是“类”,则在概念上是一个引用,如果使用let
,则该引用是一个常量。如果CTest
是一个结构体,则您的所有letTest
分配都不起作用。 - JeremyPstruct
,那么它就是值类型,没有任何概念上的问题。同样的,class
也是引用类型。
当修改值类型时,你会创建一个该类型的新实例。
https://developer.apple.com/swift/blog/?id=10
因此,显然你不能修改绑定到值类型的 let
字段/属性。 - KrzakSwift let vs var
let
- constant
var
- variable
[Constant vs variable]
[Struct vs Class]
官方文档 docs.swift.org 表示:
let
定义的常量在设定之后不能被改变,而var
定义的变量可以在将来被设置为不同的值。
这个术语实际上描述了一种重新分配机制。
Mutability(可变性)
Mutability - 可更改的 - 对象的状态可以在创建后被更改[相关]
引用类型(Class)
Swift 的 class
默认是可变
的
var
+class
它可以被重新分配或更改
let
+class
=地址常量
它不能被重新分配,但可以更改
值类型(Struct, Enum)
Swift 的 struct
可以更改它们的可变性状态:
var
+struct
=可变
它可以被重新分配或更改
let
+struct
=*不可变
或者更确切地说是不可修改的
[相关] [示例] [示例]=数值常量
它不能被重新分配或更改
*不可变 - 请检查 testStructMutability
测试
实验:
class MyClass {
var varClass: NSMutableString
var varStruct: String
let letClass: NSMutableString
let letStruct: String
init(_ c: NSMutableString, _ s: String) {
varClass = c
varStruct = s
letClass = c
letStruct = s
}
}
struct MyStruct {
var varClass: NSMutableString
var varStruct: String
let letClass: NSMutableString
let letStruct: String
init(_ c: NSMutableString, _ s: String) {
varClass = c
varStruct = s
letClass = c
letStruct = s
}
//mutating function block
func function() {
// varClass = "SECONDARY propertyClass" //Cannot assign to property: 'self' is immutable
// varStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'self' is immutable
}
mutating func mutatingFunction() {
varClass = "SECONDARY propertyClass"
varStruct = "SECONDARY propertyStruct"
}
}
可能的使用案例
func functionVarLetClassStruct() {
var varMyClass = MyClass("propertyClass", "propertyStruct")
varMyClass.varClass = "SECONDARY propertyClass"
varMyClass.varStruct = "SECONDARY propertyStruct"
// varMyClass.letClass = "SECONDARY propertyClass" //Cannot assign to property: 'letClass' is a 'let' constant
// varMyClass.letStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letStruct' is a 'let' constant
let letMyClass = MyClass("propertyClass", "propertyStruct")
letMyClass.varClass = "SECONDARY propertyClass"
letMyClass.varStruct = "SECONDARY propertyStruct"
// letMyClass.letClass = "SECONDARY propertyClass" //Cannot assign to property: 'letClass' is a 'let' constant
// letMyClass.letStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letStruct' is a 'let' constant
var varMyStruct = MyStruct("propertyClass", "propertyStruct")
varMyStruct.varClass = "SECONDARY propertyClass"
varMyStruct.varStruct = "SECONDARY propertyStruct"
// varMyStruct.letClass = "SECONDARY propertyClass" //Cannot assign to property: 'letClass' is a 'let' constant
// varMyStruct.letStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letStruct' is a 'let' constant
let letMyStruct = MyStruct("propertyClass", "propertyStruct")
// letMyStruct.varClass = "SECONDARY propertyClass" //Cannot assign to property: 'letMyStruct' is a 'let' constant
// letMyStruct.varStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letMyStruct' is a 'let' constant
// letMyStruct.letClass = "SECONDARY propertyClass" //Cannot assign to property: 'letClass' is a 'let' constant
// letMyStruct.letStruct = "SECONDARY propertyStruct" //Cannot assign to property: 'letStruct' is a 'let' constant
}
mutating
- 更改结构体函数你可以将结构体中的方法标记为mutating
var
变量上调用可变函数func testStructMutatingFunc() {
//given
var varMyStruct = MyStruct("propertyClass", "propertyStruct")
//when
varMyStruct.mutatingFunction()
//than
XCTAssert(varMyStruct.varClass == "SECONDARY propertyClass" && varMyStruct.varStruct == "SECONDARY propertyStruct")
// It is not possible to call a mutating function on a let variable
let letMyStruct = MyStruct("propertyClass", "propertyStruct")
// letMyStruct.mutatingFunction() //Cannot use mutating member on immutable value: 'letMyStruct' is a 'let' constant
}
inout
函数参数inout
可以让你重新分配/修改传递(原始)值。inout
参数中传递var
变量inout
的下一个流程如下:
//InOut
func functionWithInOutParameter(a: inout MyClass, s: inout MyStruct) {
a = MyClass("SECONDARY propertyClass", "SECONDARY propertyStruct") //<-- assign
s = MyStruct("SECONDARY propertyClass", "SECONDARY propertyStruct") //<-- assign
}
func testInOutParameter() {
//given
var varMyClass = MyClass("PRIMARY propertyClass", "PRIMARY propertyStruct")
var varMyStruct = MyStruct("PRIMARY propertyClass", "PRIMARY propertyStruct")
//when
functionWithInOutParameter(a: &varMyClass, s: &varMyStruct)
//then
XCTAssert(varMyClass.varClass == "SECONDARY propertyClass" && varMyClass.varStruct == "SECONDARY propertyStruct")
XCTAssert(varMyStruct.varClass == "SECONDARY propertyClass" && varMyStruct.varStruct == "SECONDARY propertyStruct")
// It is not possible to pass let into inout parameter
let letMyClass = MyClass("PRIMARY propertyClass", "PRIMARY propertyStruct")
let letMyStruct = MyStruct("PRIMARY propertyClass", "PRIMARY propertyStruct")
// functionWithInOutParameter(a: &letMyClass, s: &letMyStruct) //Cannot pass immutable value as inout argument: 'letMyClass', 'letMyStruct' are 'let' constants
}
你仍然可以改变let + struct
func testStructMutability() {
//given
let str: NSMutableString = "propertyClass"
let letMyStruct = MyStruct(str, "propertyStruct")
//when
str.append(" SECONDARY")
//then
XCTAssert(letMyStruct.letClass == "propertyClass SECONDARY")
}
尽可能使用
let
。当必须时使用var
。
let
用于定义常量,var
用于定义变量。
与C语言类似,Swift使用变量来存储和引用通过标识名称识别的值。Swift还广泛使用变量,其值无法更改。这些被称为常量,并且比C中的常量更为强大。在Swift中,常量在处理不需要更改的值时,在整个代码中都是安全且意图更清晰的。
https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html
let aInt = 1 //< aInt is not changeable
var aInt = 1 //< aInt can be changed
let aPerson = Person(name:Foo, first:Bar)
//< data of aPerson are changeable, not the reference
var aPerson = Person(name:Foo, first:Bar)
//< both reference and data are changeable.
例如:
var aPersonA = Person(name:A, first: a)
var aPersonB = Person(name:B, first: b)
aPersonA = aPersonB
aPersonA now refers to Person(name:B, first: b)
并且
let aPersonA = Person(name:A, first: a)
let aPersonB = Person(name:B, first: b)
let aPersonA = aPersonB // won't compile
let aPersonA = Person(name:A, first: a)
aPersonA.name = "B" // will compile
aPerson
有setter,你可以修改它的属性,对吧?所以let
并没有使Person
成为不可变的。 - drewish非常简单:
let
是常量。var
是动态的。一些说明:
let
创建一个常量(类似于 NSString
)。一旦设置了它的值,就不能再更改它。但是您仍然可以将其添加到其他内容并创建新变量。
var
创建一个变量(类似于 NSMutableString
),因此您可以更改其值。但是这个问题已经被解决了很多次。
let
定义了一个“常量”。它的值只能被设置一次,尽管不一定要在声明时设置。例如,在类中使用 let
定义一个必须在初始化期间设置的属性:
class Person {
let firstName: String
let lastName: String
init(first: String, last: String) {
firstName = first
lastName = last
super.init()
}
}
Person(first:"Malcolm", last:"Reynolds")
来创建一个Person
实例之后,将无效地分配给firstName
或lastName
。let
或var
)定义类型,并且任何试图设置变量的代码只能使用该类型(或子类型)。您可以在运行时分配值,但其类型必须在编译时知道。let
用于声明一个常量值-一旦给它赋予了初始值,就不能更改它。
var
用于声明一个变量值-您随意可以更改它的值。
我遇到的其他语言中常量的另一个区别是:无法在稍后初始化常量(let),应该在声明常量时进行初始化。
例如:
let constantValue : Int // Compile error - let declarations require an initialiser expression
var variableValue : Int // No issues
let num: Int
,然后是:if someCondition { num = 42 } else { num = 100 }
。只要在声明和赋值的代码行之间没有其他代码,它就可以跨行分割。 - HangarRash