swift中的let和var有什么区别?


321

letvarApple的Swift语言有什么区别?

以我的理解,它是一种编译语言,但它不会在编译时检查类型。这让我感到困惑。编译器如何知道类型错误?如果编译器不检查类型,那么生产环境是否存在问题?


35
let是常量,var是变量。
Collin Henderson

2
@Edward在编译时不进行类型检查是什么意思?据我所知,它是静态类型的,但是如果编译器可以自行找出类型,则可以推断出类型。但是我只在第25页... ;-)
Joachim Isaksson 2014年

4
这是一个话题,但措辞不好。至少有两个问题(i)letvar之间的区别;(ii)类型安全与类型推断。另外,当海报提到生产阶段时,他的意思是在运行时。
凯文·勒-Khnle 2014年

1
另外,在定义集合(数组和字典)的变量上使用的var创建一个可变的集合(不仅是引用,还可以修改集合的内容。var的其他用法是可以修改在函数中传递的参数:func foo(var bar:Int)将允许您在函数范围内本地修改param bar
Laurent

Answers:


407

let关键字定义一个常数:

let theAnswer = 42

theAnswer无法改变之后。这就是为什么weak不能使用编写任何内容的原因let。它们需要在运行时进行更改,而您必须在使用它们var

var定义了一个普通变量。

有趣的是:

常量的值不需要在编译时就知道,但是您必须精确地分配一次值。

另一个奇怪的功能:

对于常量和变量名称,几乎可以使用任何喜欢的字符,包括Unicode字符:

let 🐶🐮 = "dogcow"

摘自:Apple Inc.“ Swift编程语言”。iBooks。https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=881256329

编辑

因为评论要求在答案中添加其他事实,所以将其转换为社区Wiki答案。随意编辑答案以使其更好。


1
C和C ++也通过UCN允许Unicode标识符。如果编译器支持任何Unicode源编码,那么您可以直接使用Unicode字符。例如,auto 🐶🐮 = "dogcow";在C ++中适用于clang。
bames53 2014年

131
@ bames53好的,我不确定是否要调试这样的程序:: if 😍 === 💝 { 💔 = ♠︎ });)
jm666 2014年

它适用于REPL吗?因为您可以在REPL中重新分配常数。
Ahmed Al Hafoudh 2014年

1
首先,如上所述,这在REPL中完全不同。其次,如果它是一个常数,则它不是一个常数。这在编译器中可以正常工作:let foo = [1,2,3]; foo [2] = 5; println(“(foo)”)// [
凯文·弗罗斯特

31
这个答案虽然最受支持,但却没有提到在引用对象而不是值类型时let / var的行为。关键在于,在两种情况下,您仍然可以更改对象的属性,但是不能修改指针以引用另一个对象。从涉及整数和字符串的基本示例中,这并不是立即显而易见的。
SaltyNuts 2015年

33

根据《The Swift Programming Language Book》

与C一样,Swift使用变量来存储和引用具有标识名称的值。Swift还广泛使用了无法更改其值的变量。这些被称为常量,并且比C中的常量强大得多。

两个varlet引用,因此let是一个常量引用。使用基本类型并没有真正显示letconst。与类实例(引用类型)一起使用时会有所不同:

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"

1
这个术语是完全错误的...所有引用的确是const引用。没有“ const ref”的概念。一旦绑定,引用将始终绑定到相同的内存地址,并且不能更改或“取消固定”。我相信您的意思是var是“指针”,而让它是“ const指针”
AyBayBay 2015年

@AyBayBay虽然您在C ++中编写的内容是正确的,但我认为上面的代码片段证明了,在Swift中并非如此。指针将允许指针算术和直接存储器访问,在此情况下也不是这种情况。-编辑:我发现没有证据表明所有引用确实是const引用对每种编程语言都是正确的。
2015年

根据维基百科的指点,BTW 是参考
Krzak

2
我同意您的术语是错误的。 varlet绑定的标识符是否为引用无关。如果类型是struct类型,则从概念上讲是值。如果类型是a class,则从概念上讲是一个引用,如果let使用,则引用是一个常量。如果CTest是一个结构体,那么您的任何letTest分配都不会起作用。
JeremyP 2015年

1
如果类型是struct值类型,则没有任何概念上的意义。与class-引用类型相同。修改值类型时,将创建此类型的新实例。developer.apple.com/swift/blog/?id=10因此,显然您不能修改let绑定到值类型的字段/属性。
2015年


7

最好通过“可变性/不可更改性”概念来说明这种差异,该概念是“对象”空间中值和实例可变性的正确范例,比唯一的“常数/变量”常规概念更大。而且,这更接近于Objective C方法。

2种数据类型:值类型和引用类型。

在值类型的上下文中:

“ let”定义一个恒定值(不可调整)。“ var”定义一个可变值(可变)。

let aInt = 1   //< aInt is not changeable

var aInt = 1   //< aInt can be changed

在引用类型的上下文中:

数据的标签不是值,而是对值的引用。

如果aPerson = Person(姓名:Foo,第一名: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.

eg:
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)

1
但是如果aPerson有设置员,您可以修改其属性吗?所以let不会使Person不可变的。
drewish

4
不变性?那是不可能的!当然是不可取的。我认为您说的是您所寻找的可能是“不变性” :-)
paxdiablo 2014年

6

Swift编程语言文档的“ 声明常量和变量”部分指定了以下内容:

您可以使用let关键字声明常量,并使用var关键字声明变量。

确保了解它对于引用类型的工作方式。与值类型不同,尽管引用类型的实例被声明为常量,但对象的基础属性仍可能发生变化。请参阅文档的“ 类是引用类型”部分,并查看示例它们在其中更改frameRate属性的示例。


5

很简单:

  • let 是恒定的。
  • var 是动态的。

描述位:

let创建一个常数。(有点像NSString)。设置后就无法更改其值。您仍然可以将其添加到其他内容并创建新变量。

var创建一个变量。(有点像NSMutableString),因此您可以更改它的值。但这已经被回答了好几次了。


4

let定义一个“常量”。它的值只设置一次,并且一次设置,尽管不一定要在声明时设置。例如,您用于let在必须在初始化期间设置的类中定义属性:

class Person {

    let firstName: String
    let lastName: String

    init(first: String, last: String) {
         firstName = first
         lastName = last
         super.init()
    }
}

使用此设置,在调用(例如)创建实例时分配firstName或分配给实例是无效的。lastNamePerson(first:"Malcolm", last:"Reynolds")Person

必须在编译时为所有变量(letvar)定义一种类型,任何试图设置变量的代码都只能使用该类型(或子类型)。您可以在运行时分配一个,但是在编译时必须知道其类型


4

let- constant
var-variable

[常量与变量]
[结构与类]

官方文件docs.swift.org

a的值一经设置constant就无法更改,而variable将来可以将其设置为其他值。

该术语实际上描述了重新分配机制

可变性-可更改-创建后可以更改对象的状态

值和引用类型[关于]

值(结构,枚举)

Swift struct可以更改其可变性状态:

let+ struct= immutable= 的值恒定
它可以重新分配改变

var+ struct= mutable
可以重新分配更改

参考类型(类)

斯威夫特的classesmutableA-修道院

let+ class= 地址的常数
它可以重新分配,并且可以改变

var+ class
可以重新分配更改

//STRUCT
  //let + struct
let letStructA = StructA()

    //change FAIL
letStructA.a = 5 //Compile ERROR: Cannot assign to property: 'structALet' is a 'let' constant

    //reassign FAIL
letStructA = StructA() // Compile ERROR: Cannot assign to value: 'structALet' is a 'let' constant

  //var + struct
var varStructA = StructA()

    //change OK
varStructA.a = 5

    //reassign OK
varStructA = StructA()

//CLASS
  //let + class
let letClassA = ClassA()

    //change OK
letClassA.a = 5

    //reassign FAIL
letClassA = ClassA() // Compile ERROR: Cannot assign to value: 'classALet' is a 'let' constant

  //var + class
var varClassA = ClassA()

    //change OK
varClassA.a = 5

    //reassign OK
varClassA = ClassA()

mutating -改变结构的功能

您可以将结构的方法标记为mutating

  1. 指示此函数更改内部属性值。
  2. 只能在var+上使用struct
public struct StructA {
    public var a = 0

    public init() {}

    //func foo() { //Compile ERROR: Cannot assign to property: 'self' is immutable
    mutating func foo() {
        a = 5
    }
}

inout 在函数内部修改结构

您可以将函数的参数(结构)标记为 inout

由于struct是值类型,因此按传递它,因为结果函数将检索副本。如果将a标记structinout参数,则表示此参数变为,var并且您可以更改其状态,struct并且这些更改将在功能范围之外可见

//func foo(myStruct: StructA) { //Compile ERROR: line - myStruct.a = 10: Cannot assign to property: 's' is a 'let' constant
func foo(myStruct: inout StructA) {
    myStruct.a = 10
}

//using
//foo(myStruct: &letStructA) // Compile EROOR: Cannot pass immutable value as inout argument: 'letStructA' is a 'let' constant
foo(myStruct: &varStructA)

let尽可能使用。var必要时使用。


2

在常量的其他语言中,我遇到的另一个不同是:不能为稍后初始化常量(let)应在要声明常量时进行初始化。

例如 :

let constantValue : Int // Compile error - let declarations require an initialiser expression

变量

var variableValue : Int // No issues 

2

let用于声明一个常数值-在给定初始值后您将不会对其进行更改。
var用于声明变量值-您可以根据需要更改其值。


1

let用于定义常量,而 var用于定义变量。您可以定义使用字符串 VAR然后特定字串可以通过将其分配给一个变量(在这种情况下,可以修改)被修改(或突变),如果你定义字符串使用它是一个常数(在这种情况下,不能改性):

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

0

let关键字定义一个常量

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 x = 7 // here also x is instantiated with 7 
x = 99 // this will a compile time error

0

像Luc-Oliver一样,NullData和其他一些人在这里说的是,let定义不可变数据而var定义可变数据。只能在func被标记的变量上调用的任何变量都mutating可以被调用var(编译器将引发错误)。这也适用func于接受inout变量的。

然而,letvar也意味着变量不能被重新分配。它有两种含义,两者的目的非常相似


0

初始化后,可以更改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。但是尝试使用可变数组和可变字符串,您可以通过添加或附加值来更改其值。正确的是对象不能通过其指针更改,它们的指针地址将始终相同,这就是为什么您要重新初始化错误的原因。因此可以说, const指针将来不能更改。
TheTiger

Swift中没有console.log。检查OP的标签
Dan Beaulieu

0

关键字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 

0

Let是一个不可变的变量,表示它不能更改,其他语言将此称为常量。在C ++中,您可以将其定义为const。

Var是可变变量,表示可以更改。在C ++(2011年版本更新)中,它与使用auto相同,但是swift允许更灵活的使用。对于初学者来说,这是更为知名的变量类型。


0

let是一个恒定值,因此永远无法更改。

let number = 5  
number = 6               //This will not compile.

Var是一个变量,可以更改(但是在将其定义为其他数据类型之后)。

var number = 5
number = 6               //This will compile.

如果您尝试将变量更改为其他dataType,它将无法正常工作

var number = 5
number = "Hello World"   //This will not compile.

1
咱们应该
TheTiger

0

主要区别在于var变量值可以更改,而let不能更改。如果要让用户输入数据,则可以使用,var以便可以更改值,而可以使用letdatatype变量,以便不能更改值。

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)。
Abhishek 2015年

0

如果是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.


0

var是变量,可以根据需要多次更改

例如

var changeit:Int=1
changeit=2
 //changeit has changed to 2 

let是常量,无法更改

例如

let changeit:Int=1
changeit=2
 //Error becuase constant cannot be changed

0

即使let和var之间已经有很多区别,但是一个主要区别是:

let is compiled fast in comparison to var.

-1

每个人都几乎回答了这个问题,但这是一种可以记住什么的方法

让我们总是说“让”,就像让它一次又一次地像“ var”变量总是可以改变一样,因此将它们称为变量


-1

var是快速创建变量的唯一方法。var并不像javascript之类的解释语言一样表示动态变量。例如,

var name = "Bob"

在这种情况下,name可以推断变量的类型为name为type String,我们还可以通过显式定义type来创建变量,例如

var age:Int = 20

现在,如果将字符串分配给age,则编译器将给出错误信息。

let用于声明常量。例如

let city = "Kathmandu"

或者我们也可以

let city:String = "Kathmandu"

如果尝试更改city的值,则在编译时会出错。


-1

let用于常量,而var是普通变量时不能修改

例:

let name =“ Bob”,诸如name =“ Jim”之类的东西将引发错误,因为无法修改常量。


-1

简单差异

let =(无法更改)

var =(随时更新)


1
这似乎只是许多现有答案的重复。

-1

资料来源: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 keyword”创建了一个新变量“ a”,并为其分配了值“ 1”。当我打印“ a”时,输出为1。然后将2分配给“ var a”,即我正在修改变量“ a”的值。我可以做到这一点而不会出现编译器错误,因为我将其声明为var。

在第二种情况下,我使用“ let关键字”创建了一个新变量“ b”,并为其分配了值“ 4”。当我打印“ b”时,我得到4作为输出。然后,我尝试将5赋给“ let b”,即我试图修改“ let”变量,然后出现编译时错误“无法分配给值:'b'为'let'常量”。


-3

尽管目前我仍在阅读手册,但是我认为这与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

由于这些结构默认情况下是不可变的,因此您需要使用标记一个mutator方法mutating。并且由于名称aaa1是常量,因此您无法在其上调用任何mutator方法。这正是我们对C / C ++指针的期望。

我相信这是一种支持const正确性的机制。


-3

使用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


-4

找到了一个很好的答案,希望可以帮助您:) 在此处输入图片说明


4
这实际上是不正确的。let并不意味着对象是不可变的,而是意味着指针是不可变的。要获得Obj-C中的等效功能,您需要使用NSObject *const myObject = someobject;-可以修改此类对象的属性,但myObject不能修改指针以指向另一个对象。
SaltyNuts 2015年

1
完全错误的答案。您是否尝试过让数组:NSMutableArray = NSMutableArray()?您可以为此添加对象或从中删除对象。品牌const pointer不能在未来的变化,但它的价值就可以了。您不能重新初始化它,但可以根据需要使用它。
TheTiger 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.