Swift 中的 `let` 和 `var` 有啥区别?
Posted
技术标签:
【中文标题】Swift 中的 `let` 和 `var` 有啥区别?【英文标题】:What is the difference between `let` and `var` in Swift?Swift 中的 `let` 和 `var` 有什么区别? 【发布时间】:2014-07-23 00:24:37 【问题描述】:let
和 var
在 Apple 的 Swift 语言中有什么区别?
据我了解,它是一种编译语言,但它不会在编译时检查类型。这让我很困惑。编译器如何知道类型错误?如果编译器不检查类型,是不是生产环境有问题?
当我尝试为 let
赋值时出现此错误:
无法分配给属性:“variableName”是“let”常量 将 'let' 更改为 'var' 以使其可变
【问题讨论】:
let 用于常量,var 用于变量。 @Edward 在编译时没有类型检查是什么意思?据我所知,它是静态类型的,但是如果编译器可以自己找出类型,则会推断出类型。但后来我只在第 25 页... ;-) 这是一个主题但措辞不佳的问题。至少有 2 个问题 (i) let 和 var 之间的区别; (ii) 类型安全与类型推断。另外,当发帖人提到制作阶段时,他的真正意思是在运行时。 此外,用于定义集合(数组和字典)的变量的 var 创建一个可变集合(不仅是引用,而且集合的内容可以修改。var 的其他用法是能够修改函数中传递的参数: func foo(var bar:Int) 将允许您在函数范围内本地修改参数栏。 Differentiate let and var in Swift Programming Language的可能重复 【参考方案1】:let
关键字定义了一个常量:
let theAnswer = 42
theAnswer
之后无法更改。这就是为什么不能使用let
编写任何weak
的原因。它们需要在运行时更改,而您必须改用var
。
var
定义了一个普通变量。
有趣的是:
常量的值不需要在编译时知道,但你必须只分配一次值。
另一个奇怪的功能:
您几乎可以使用任何您喜欢的字符作为常量和变量 名称,包括 Unicode 字符:
let ?? = "dogcow"
摘自:Apple Inc.“Swift 编程语言”。电子书。 https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=881256329
社区维基
因为 cmets 要求在答案中添加其他事实,将其转换为 community wiki answer。随意编辑答案以使其更好。
【讨论】:
C 和 C++ 也允许通过 UCN 使用 Unicode 标识符。如果编译器支持任何 Unicode 源编码,那么您可以直接使用 Unicode 字符。例如auto ?? = "dogcow";
在 C++ 中为 clang 工作。
@bames53 好吧,我只是不确定是否要调试一个程序,例如:if ? === ? ? = ♠︎
:) ;)
它适用于 REPL 吗?因为你可以在 REPL 中重新分配常量。
首先,如上所述,这在 REPL 中是完全不同的。其次,如果它是一个常数,那么它就不是一个常数。这在编译器中工作得很好: let foo = [1,2,3];富[2] = 5; println("(foo)") // [1, 2, 5]
这个答案虽然是最受好评的,但没有提到当引用对象而不是值类型时 let/var 的行为方式。关键是在这两种情况下你仍然可以改变对象的属性,但不能修改指针来引用另一个对象。这在涉及整数和字符串的基本示例中并不是很明显。【参考方案2】:
let
用于定义常量,var
用于定义变量。
与 C 一样,Swift 使用 变量 来存储和通过标识名称引用值。 Swift 还广泛使用了值无法更改的变量。这些被称为常量,比 C 中的常量更强大。常量在整个 Swift 中使用,以便在您使用不需要更改的值时使代码更安全、更清晰。
https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html
【讨论】:
【参考方案3】: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
)定义一个类型,并且任何尝试设置变量的代码只能使用该类型(或子类型) .您可以在运行时分配一个值,但它的类型必须在编译时知道。
【讨论】:
【参考方案4】:虽然目前我仍在阅读手册,但我认为这非常接近 C/C++ const
指针。换句话说,类似于char const*
和char*
之间的区别。编译器也拒绝更新内容,不仅引用重新赋值(指针)。
例如,假设你有这个结构。注意这是一个结构,而不是一个类。 AFAIK,类没有不可变状态的概念。
import Foundation
struct
AAA
var inner_value1 = 111
mutating func
mutatingMethod1()
inner_value1 = 222
let aaa1 = AAA()
aaa1.mutatingMethod1() // compile error
aaa1.inner_value1 = 444 // compile error
var aaa2 = AAA()
aaa2.mutatingMethod1() // OK
aaa2.inner_value1 = 444 // OK
因为结构体默认是不可变的,所以你需要用mutating
标记一个mutator方法。并且因为名称 aaa1
是常量,所以您不能在其上调用任何 mutator 方法。这正是我们对 C/C++ 指针的期望。
我相信这是一种支持const-correctness stuff的机制。
【讨论】:
【参考方案5】:在 var 的情况下可以重新赋值
//Variables
var age = 42
println(age) //Will print 42
age = 90
println(age) //Will Print 90
** newAge 常量不能重新分配给新值。尝试这样做会产生编译时错误**
//Constants
let newAge = 92 //Declaring a constant using let
println(newAge) //Will print 92.
【讨论】:
【参考方案6】:let
用于声明一个常量值 - 给它一个初始值后你不会更改它。var
用于声明一个变量值 - 你可以根据需要更改它的值。
【讨论】:
【参考方案7】:用 let 关键字声明常量,用 var 关键字声明变量。
let maximumNumberOfLoginAttempts = 10 var currentLoginAttempt = 0
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
在一行中声明多个常量或多个变量,用逗号分隔:
var x = 0.0, y = 0.0, z = 0.0
打印常量和变量
您可以使用 println 函数打印常量或变量的当前值:
println(friendlyWelcome)
Swift 使用字符串插值将常量或变量的名称作为占位符包含在较长的字符串中
将名称括在括号中,并在左括号前用反斜杠转义:
println("The current value of friendlyWelcome is \(friendlyWelcome)")
参考:http://iosswift.com.au/?p=17
【讨论】:
【参考方案8】:通过可变性/不变性概念来说明这种差异可能更好,这是对象空间中值和实例可变性的正确范例,它大于唯一的“常量/变量”通常概念。 此外,这更接近于 Objective C 方法。
2种数据类型:值类型和引用类型。
在值类型的上下文中:
'let' 定义一个常量值(不可变)。 'var' 定义了一个可变的值(可变的)。
let aInt = 1 //< aInt is not changeable
var aInt = 1 //< aInt can be changed
在引用类型的上下文中:
数据的标签不是值而是对值的引用。
如果 aPerson = Person(name:Foo, first:Bar)
aPerson 不包含此人的数据,而是对此人数据的引用。
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
有设置器,你可以修改它的属性对吗?所以let
不会使Person
不可变。
不变性?那是不可能的!当然是不明智的。我认为您正在寻找的词可能是“不变性”:-)【参考方案9】:
Declaring Constants and Variables Swift 编程语言文档的部分指定了以下内容:
用 let 关键字声明常量,用 var 关键字声明变量。
确保了解这对引用类型的工作原理。与值类型不同,尽管引用类型的实例被声明为常量,但对象的底层属性仍可能发生变化。请参阅文档的 Classes are Reference Types 部分,并查看他们更改 frameRate 属性的示例。
【讨论】:
【参考方案10】:我在其他语言中遇到的关于常量的另一个区别是:不能为以后初始化常量(let),应该初始化因为你即将声明常量。
例如:
let constantValue : Int // Compile error - let declarations require an initialiser expression
变量
var variableValue : Int // No issues
【讨论】:
【参考方案11】:“使用 let 生成常量,使用 var 生成变量”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itun.es/us/jEUH0.l
【讨论】:
【参考方案12】:根据The Swift Programming Language Book
与 C 一样,Swift 使用变量来存储和引用值 识别名称。 Swift 还广泛使用了变量 值不能更改。这些被称为常数,并且很多 比 C 中的常量更强大。
var
和let
都是引用,因此let
是const 引用。
使用基本类型并不能真正显示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"
【讨论】:
这个术语是完全错误的......所有引用确实是 const 引用。没有“const ref”的概念。一旦绑定,引用总是绑定到相同的内存地址,并且不能更改或“取消定位”。我相信你的意思是 var 是一个“指针”,而 let 是一个“const 指针” @AyBayBay 虽然您所写的内容是正确的,例如C++ 我认为上面的 sn-p 证明,在 Swift 中并非如此。指针将允许指针算术和直接内存访问,这又不是这里的情况。 -- 编辑:我没有发现任何证据表明所有引用确实是 const 引用对于每种编程语言都是正确的。 BTW 根据Wikipedia 指针是引用 我同意你的术语是错误的。var
和 let
与被绑定的标识符是否为引用无关。如果类型是struct
类型,则它在概念上是一个值。如果类型是class
,它在概念上是一个引用,如果使用let
,则该引用是一个常量。如果CTest
是一个结构,那么您的letTest
分配都不会起作用。
如果类型是struct
,它是一个值类型,它没有任何概念。与 class
相同 - 引用类型。修改值类型时,您会创建此类型的新实例。 developer.apple.com/swift/blog/?id=10 所以显然你不能修改绑定到值类型的let
的字段/属性。【参考方案13】:
let 用于定义常量,var 用于定义变量。 您使用 var 定义字符串,然后可以通过将特定字符串分配给变量来修改(或变异)(在这种情况下可以修改),如果您定义使用 let 的字符串是一个常量(在这种情况下不能修改):
var variableString = "Apple"
variableString += " and Banana"
// variableString is now "Apple and Banana"
let constantString = "Apple"
constantString += " and another Banana"
// this reports a compile-time error - a constant string cannot be modified
【讨论】:
【参考方案14】:let 是一个常数值,所以永远不能改变。
let number = 5
number = 6 //This will not compile.
Var 是一个变量,可以改变(但在它被定义为不同的数据类型之后。)
var number = 5
number = 6 //This will compile.
如果您尝试将变量更改为不同的数据类型,它将不起作用
var number = 5
number = "Hello World" //This will not compile.
【讨论】:
让应该是让。【参考方案15】:让关键字定义一个常量
let myNum = 7
所以 myNum 之后不能更改;
但是 var 定义了一个普通的变量。
常量的值不需要在编译时就知道,但你必须给它赋值一次。
您几乎可以使用任何您喜欢的字符作为常量和变量名称,包括 Unicode 字符;
例如
var x = 7 // here x is instantiated with 7
x = 99 // now x is 99 it means it has been changed.
但是如果我们采取 let 那么...
let x = 7 // here also x is instantiated with 7
x = 99 // this will a compile time error
【讨论】:
【参考方案16】:主要区别在于var
变量值可以改变,而let
不能。如果您想要用户输入数据,您将使用var
以便可以更改值并使用let
数据类型变量因此无法更改值。
var str = "dog" // str value is "dog"
str = "cat" // str value is now "cat"
let strAnimal = "dog" // strAnimal value is "dog"
strAnimal = "cat" // Error !
【讨论】:
Let 和 Var 不能在小写字母中使用 (let 和 var)。【参考方案17】:找到了一个很好的答案希望它可以帮助:)
【讨论】:
这实际上是不正确的。let
并不是说 object 是不可变的,而是说 pointer 是不可变的。要在 Obj-C 中获得等效功能,您需要使用 NSObject *const myObject = someobject;
- 可以修改此类对象的属性,但不能修改指针 myObject
以指向另一个对象。
完全错误的答案。您是否尝试过 let 数组:NSMutableArray = NSMutableArray() ?您可以在其中添加和删除对象。 let 使 const pointer
以后不能改变,但它的值可以。您不能重新初始化它,但可以根据需要使用它。【参考方案18】:
就像 Luc-Oliver、NullData 和其他一些人在这里所说的那样,let
定义不可变数据,而 var
定义可变数据。任何可以在标记为mutating
的变量上调用的func
只能在它是var
变量时调用(编译器会抛出错误)。这也适用于接受inout
变量的func
。
但是,let
和var
也意味着不能重新分配变量。它有两种含义,目的都非常相似
【讨论】:
【参考方案19】:很简单:
let
是不变的。
var
是动态的。
一点描述:
let
创建一个常量。 (有点像NSString
)。一旦你设置了它,你就不能改变它的值。不过,您仍然可以将其添加到其他事物中并创建新变量。
var
创建一个变量。 (有点像NSMutableString
)所以你可以改变它的价值。但这已经回答了好几次了。
【讨论】:
【参考方案20】:var 值可以在初始化后更改。但是让值不会被改变,当它被激活一次时。
如果是 var
function variable()
var number = 5, number = 6;
console.log(number); // return console value is 6
variable();
如果让
function abc()
let number = 5, number = 6;
console.log(number); // TypeError: redeclaration of let number
abc();
【讨论】:
但让价值不会改变,当它被激活一次时。我不同意这一点。您的评论适用于 int、float 等非对象值。但是尝试使用可变数组和可变字符串,您可以通过添加或附加值来更改它们的值。正确的是 let 对象不能通过其指针更改,它们的指针地址将始终相同,这就是您收到重新初始化错误的原因。所以你可以说 let 使 const 指针在未来不能改变。 Swift 中没有 console.log。检查OP的标签【参考方案21】:几乎每个人都回答了这个问题,但这里有一种方法可以让你记住是什么
让我们总是说“让”的想法和让这个工作一次一样,总是因为“var”变量总是可以改变,因此它们被称为变量的
【讨论】:
【参考方案22】:关键字 var 用于定义一个变量,您可以像这样轻松更改其值:
var no1 = 1 // declaring the variable
no1 = 2 // changing the value since it is defined as a variable not a constant
但是,let 关键字仅用于创建一个常量,当您不想再次更改常量的值时使用。如果你尝试改变常量的值,你会得到一个错误:
let no2 = 5 // declaring no2 as a constant
no2 = 8 // this will give an error as you cannot change the value of a constant
【讨论】:
【参考方案23】:Let 是一个不可变的变量,意味着它不能被改变,其他语言称之为常量。在 C++ 中,您可以将其定义为 const。
Var 是一个可变变量,意味着它可以被改变。在 C++(2011 版本更新)中,它与使用 auto 相同,但 swift 允许在使用上更加灵活。这是初学者比较熟悉的变量类型。
【讨论】:
【参考方案24】:var
是在 swift 中创建变量的唯一方法。 var
并不意味着动态变量,就像 javascript 这样的解释语言。例如,
var name = "Bob"
在这种情况下,变量name
的类型推断为name的类型为String
,我们也可以通过显式定义类型来创建变量,例如
var age:Int = 20
现在,如果您将字符串分配给年龄,则编译器会给出错误。
let
用于声明常量。例如
let city = "Kathmandu"
或者我们也可以,
let city:String = "Kathmandu"
如果你试图改变city的值,编译时会报错。
【讨论】:
【参考方案25】:let 用于不能修改的常量,而 var 是普通变量
例子:
让名称 = “鲍勃” 像 name = “Jim” 这样的东西会抛出一个错误,因为常量不能被修改。
【讨论】:
【参考方案26】:var 是变量,可以随心所欲地更改多次
例如
var changeit:Int=1
changeit=2
//changeit has changed to 2
让是不变的,不能改变
例如
let changeit:Int=1
changeit=2
//Error becuase constant cannot be changed
【讨论】:
【参考方案27】:即使您已经在 let 和 var 之间找到了很多区别,但一个主要区别是:
let is compiled fast in comparison to var.
【讨论】:
【参考方案28】:简单的区别
let =(不能更改)
var = (随时更新)
【讨论】:
这似乎只是许多现有答案的重复。【参考方案29】:来源:https://thenucleargeeks.com/2019/04/10/swift-let-vs-var/
当你用var声明一个变量时,表示它可以更新,它是变量,它的值是可以修改的。
当你用let声明一个变量时,意味着它不能被更新,它是非变量,它的值不能被修改。
var a = 1
print (a) // output 1
a = 2
print (a) // output 2
let b = 4
print (b) // output 4
b = 5 // error "Cannot assign to value: 'b' is a 'let' constant"
让我们理解上面的例子:我们用“var关键字”创建了一个新变量“a”,并赋值为“1”。当我打印“a”时,我得到的输出为 1。然后我将 2 分配给“var a”,即我正在修改变量“a”的值。我可以做到这一点而不会出现编译器错误,因为我将其声明为 var。
在第二个场景中,我使用“let 关键字”创建了一个新变量“b”并分配了值“4”。当我打印“b”时,我得到 4 作为输出。然后我尝试将 5 分配给“let b”,即我正在尝试修改“let”变量,但出现编译时错误“无法赋值:‘b’是‘let’常量”。
【讨论】:
【参考方案30】:let
- constant
var
- variable
[Constant vs variable][Struct vs Class]
官方文档docs.swift.org说
constant
的值一旦设置就无法更改,而variable
以后可以设置为不同的值。
这个术语实际上描述了一种重新分配机制
可变性
Mutability - 可变 - 对象的状态可以在创建后改变[About]
值和引用类型[About]
引用类型(类)
Swift 的 classes
是 mutable
优先级
var
+ class
可以重新分配或更改
let
+ class
= 地址常数
它可以不重新分配并且可以更改
值(结构,枚举)
Swift 的struct
可以改变它们的可变性状态:
var
+ struct
= mutable
可以重新分配或更改
let
+ struct
= *immutable
= 值常数
它可以不能重新分配或更改
*不可变 - 检查 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
。
[Mutate structure]
【讨论】:
以上是关于Swift 中的 `let` 和 `var` 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章