在Apple的Swift语言中,letvar有什么区别?

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

评论

let是常量,var是变量。

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

这是一个话题,但措辞不好。至少有两个问题(i)let和var之间的区别; (ii)类型安全与类型推断。此外,当张贴者提到生产阶段时,他的意思确实是在运行时。

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

Swift编程语言中的let和var的可能重复项

#1 楼

let关键字定义了一个常数:

let theAnswer = 42


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

var定义了一个普通变量。

有趣的是:


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


另一个奇怪的功能: />
常量和变量名几乎可以使用任何您喜欢的字符,包括Unicode字符:


let 🐶🐮 = "dogcow"


摘录来自:苹果公司。“快速编程语言”。 iBooks。 https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=881256329

EDIT

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

评论


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

– bames53
2014年6月2日20:51在

@ bames53好的,我不确定是否要调试以下程序:if😍===💝{💔=♠︎} :);)

– jm666
2014年6月2日20:58



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

–艾哈迈德·哈福德(Ahmed Al Hafoudh)
2014年6月3日在21:37



首先,如上所述,这在REPL中完全不同。其次,如果它是一个常数,那么它就不多了。这在编译器中可以正常工作:let foo = [1,2,3]; foo [2] = 5; println(“(foo)”)// [1、2、5]

–凯文·弗罗斯特
2014年6月11日20:47



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

–SaltyNuts
15年4月27日在15:56

#2 楼

根据《 Swift编程语言手册》


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


varlet都是引用,因此let是const引用。
使用基本类型并不能真正显示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"


评论


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

–AyBayBay
2015年5月9日,0:33

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

–克尔扎克
15年5月20日在16:03



根据维基百科的BTW指针是参考

–克尔扎克
15年5月20日在16:12

我同意您的术语是错误的。 var和let与绑定的标识符是否为引用无关。如果类型是结构类型,则从概念上讲是一个值。如果类型是类,则在概念上是引用,如果使用let,则引用是常量。如果CTest是一个结构,则所有letTest分配都不起作用。

– JeremyP
15年6月15日在15:52

如果类型是结构,那么它是值类型,那么就没有概念上的了。与类相同-引用类型。修改值类型时,将创建此类型的新实例。 developer.apple.com/swift/blog/?id=10显然,您不能修改let绑定到值类型的字段/属性。

–克尔扎克
2015年6月17日在8:53



#3 楼

let用于定义常量,var用于定义变量。

#4 楼

最好通过“可变性/不可变性”概念来说明这种差异,该概念是对象空间中值和实例可变性的正确范例,它比唯一的“常数/变量”通常概念大。目标C方法。
2种数据类型:值类型和引用类型。
在值类型的上下文中:在引用类型的上下文中:
数据的标签不是值,而是对值的引用。
如果aPerson = Person(名称:Foo,first:Bar)
aPerson不包含此人员的数据,而是对该人员的数据的引用。
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


评论


但是如果aPerson有设置员,您可以修改其属性,对吗?因此,let不会使Person不变。

–酒
2014年12月8日4:57



不变性?那是不可能的!当然是不可取的。我认为您要寻找的词可能是“不变性” :-)

– paxdiablo
2014-12-31 2:33



#5 楼

Swift编程语言文档的

声明常量和变量部分指定了以下内容:


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


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

#6 楼

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

class Person {

    let firstName: String
    let lastName: String

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


使用此设置,在之后分配给firstNamelastName是无效的调用(例如)Person(first:"Malcolm", last:"Reynolds")创建一个Person实例。

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

#7 楼

非常简单:let是常数。

var是动态的。

描述:

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

var创建一个变量。 (类似于NSMutableString),因此您可以更改其值。但这已经被回答了好几次了。

#8 楼

let-constant var-variable
[constant vs variable] [Struct vs Class]
官方文档docs.swift.org说

constant的值无法更改一旦设置,则将来可以将variable设置为其他值。

该术语实际上描述了一种重新分配机制。创建后更改[About]
值和引用类型[About]

引用类型(类)
Swift的classesmutable a-priory
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变量上调用mutating函数
结果在以下情况下可见变异函数已完成

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允许您重新分配/修改传递的(原始)值。
您只能在var参数内传递inout变量
函数完成后结果可见

inout下一个流程:

passed将值复制到复制的值中,然后将称为函数的函数
复制的值分配给传递的值,然后将其赋值给传递的值

//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

[可变结构]

#9 楼

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

#10 楼

我在其他语言中遇到的常量的另一个不同之处是:无法为以后初始化常量(let),应该在声明常量时初始化。

例如:

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


变量

var variableValue : Int // No issues 


#11 楼

let用于定义常量,而var用于定义变量。
使用var定义字符串,然后可以通过将特定的String分配给变量(在这种情况下可以对其进行修改)来修改(或变异)特定的String您可以使用其常量定义字符串(在这种情况下,不能对其进行修改):

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


#12 楼

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.


但是如果让我们......



#13 楼

就像Luc-Oliver,NullData和其他一些人在这里说的那样,let定义不可变数据,而var定义可变数据。可以在标记为func的变量上调用的任何mutating,仅当它是var变量时才可以调用(编译器将引发错误)。这也适用于带有func变量的inout

但是,letvar也意味着无法重新分配该变量。它有两种含义,两者的目的非常相似

#14 楼

初始化后,可以更改var值。但是,一旦使用一次,let值就不会改变。 >
  function variable() {
     var number = 5, number = 6;
     console.log(number); // return console value is 6
   }
   variable();


评论


但是让价值一旦被利用就不会改变。我不同意这一点。您的注释适合非整数值,例如int,float。但是尝试使用可变数组和可变字符串,可以通过添加或附加值来更改其值。正确的是让对象不能通过其指针更改,其指针地址将始终是相同的,这就是为什么您要重新初始化错误的原因。因此可以说,让const指针将来不能更改。

–TheTiger
15年8月3日在6:47

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

–丹·波琉(Dan Beaulieu)
16-3-15在20:25



#15 楼

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

让我们总是对“ let”说同样的想法,就像让它一次又一次地与“ var”变量一样变化,因此它们被称为变量的

#16 楼

关键字var用于定义一个变量,可以轻松更改其值,如下所示:不想再次更改常量的值。如果尝试更改常量的值,则会出现错误:

var no1 = 1 // declaring the variable 
no1 = 2 // changing the value since it is defined as a variable not a constant


#17 楼

Let是一个不可变的变量,这意味着它无法更改,其他语言将此称为常量。在C ++中,可以将其定义为const。

Var是可变变量,表示可以更改。在C ++(2011年版本更新)中,它与使用auto相同,但是swift允许更灵活的使用。这是初学者比较熟悉的变量类型。

#18 楼

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.


评论


让我们让吧。

–TheTiger
15年8月3日在6:53

#19 楼

主要区别在于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)。

–阿布舍克
15年3月25日在5:15

#20 楼

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


#21 楼

“使用let来生成常量,使用var来生成变量”

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l

#22 楼

var是变量,可以根据需要随时进行多次更改,例如






常量是常量,不能已更改

例如

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


#23 楼

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

let is compiled fast in comparison to var.


#24 楼

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

var name = "Bob"


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

var age:Int = 20


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

let用于声明常量。例如

let city = "Kathmandu"


或者我们也可以这样做,

let city:String = "Kathmandu"


如果您尝试更改的值城市,在编译时会给出错误。

#25 楼

let用于在var是普通变量的情况下不能修改的常量

示例:

let name =“ Bob”
类似于name =“ Jim”将抛出错误,因为无法修改常量。

#26 楼

简单差异

let =(无法更改)


评论


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

–庞
19 Mar 11 '19 at 0:56

#27 楼

来源: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 keyword”创建了一个新变量“ b”,并为其分配了值“ 4”。当我打印“ b”时,我得到4作为输出。然后,我尝试将5赋给“ let b”,即尝试修改“ let”变量,然后出现编译时错误“无法分配给值:“ b”是“ let”常量”。

#28 楼

虽然目前我仍在阅读手册,但我认为这非常接近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标记一个可变方法。并且由于名称aaa1是常量,因此您无法在其上调用任何mutator方法。这正是我们对C / C ++指针的期望。

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

#29 楼

用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

#30 楼

找到了一个好的答案,希望能对您有所帮助:)

评论


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

–SaltyNuts
2015年4月27日15:54



完全错误的答案。您是否尝试过让数组:NSMutableArray = NSMutableArray()?您可以为此添加对象或从中删除对象。 let使const指针将来不能更改,但其值可以更改。您不能重新初始化它,但可以根据需要使用它。

–TheTiger
15年8月3日在6:50