Swift——(六)Swift中的值类型

在Swift中,结构体和枚举类型为值类型(Structures and Enumerations),在Stack Overflow上有这样一个问题:结构体中的可变属性只有在使用mutating关键字之后才能被内置的方法修改(如果是不可变属性肯定不可以修改了,这就不用纠结了,不过在Swift中,还有一个例外,那就是构造器Initialization对于结构体和类的常量实例属性可以在构造器中进行设置,这感觉有点违背常量属性的含义,仔细想想也可以理解,因为实例化的时候,最后调用的是构造器,所以在构造器之后,实例属性的值才确定)。

@Author: twlkyao 转载或者引用请保留此行。

这里梳理下缘由,有什么不对的地方还望指出,在解决这个问题之前,有两个概念需要解释。

首先,一个值是不是可以修改并不在于它是什么类型(类还是结构体),而在于它的存储类型(常量还是变量)。只有变量才可以进行修改。

然后,值类型可以理解为每个属性都在内存中有自己的一份空间,和其它的实例之间的属性是没有关系的,值类型可以理解为一个连续的代码块,每创建一个值类型的实例,就相当于将这样的代码块复制了一份,每一份都有自己的相应的属性的值,如果实例类型是可变的,那么这个代码块中的每个属性都是可以变的,如果一个实例类型是不可变的,那么这个代码块中的每个属性也都是不可变的,每个实例类型都必须能够支持属性可变和不可变,为了满足这个条件,Swift将结构体的方法分为两类,可以修改结构体结构的和不可以修改结构体结构的,修改结构体结构的方法,必须被可变的结构体实例调用;不修改结构体结构的方法,可以被可变和不可变的结构体实例调用,而大多数情况下,使用的是后者,所以有可能苹果直接将后者作为默认情况,结构体的方法不能够修改结构体实例的属性引用类型,可以理解为指针(虽然Swift中没有指针,就像Java一样,但是面向对象的语言实际上是把类实例都当指针处理的),指向内存空间中的同一个位置,每创建一个引用类型的实例,就会多一个指针,指向这个内存地址。

好了,下边来解决这个问题,由于值类型实例可以赋值给变量或者常量,而被赋值的常量或者变量又决定了值类型实例是否可变,进而决定了值类型的实例属性是否可变,可以理解为值类型的实例属性有两种模式,可变和不可变(由属性的类型和最后被实例赋值的常量或变量决定),以下是规则:

实例属性可变性规则
实例类型(赋值号左边的类型) 实例属性类型 可变性
var let let
var var var
let let let
let var let

举例如下:

struct Point {
    var x = 0
    let y = 0
}

var a = Point()
let b = Point()

a.x = 1 // var, right.
//a.y = 2 // let, compile time error.
//b.x = 3 // let, compile time error.
//b.y = 4 // let, compile time error.

如上所示,只有在实例属性为变量,并且最终实例赋值给一个变量的时候,才可以修改相应变量的属性,而引用类型在实例化的时候,并没有进行相应的属性的复制,只是相当于添加了一个指向相应属性的指针,而属性可能又是指向其它类型的指针,所以var类型的属性还是let类型的属性,只是确定这个"指针"也就是对应关系是不是可以变

可以理解为在结构体进行实例化之前,结构体并不知道自己是不是可变的,为了防止被误修改,默认为自己是不可变的,除非在事先声明的情况才可变,这就是"mutating"关键字的作用。

下面给出代码说明值类型。

struct Point1 {
    var x = 0, y = 0
    mutating func moveToX(x: Int, andY y:Int) { // need to be a mutating method in order to work
        self.x = x
        self.y = y
    }
}

var p1 = Point1(x: 1, y: 2) // in order to change the properties, you have to use var, since it is a value type.
p1.x = 3 // works from outside the struct.
p1.moveToX(5, andY: 5)

println("p1.x = \(p1.x), p1.y = \(p1.y)")

/***************************/
struct Point2 {
    let x = 0, y = 0
}

var p2 = Point2(x: 1, y: 2)
println("p2.x=\(p2.x), p2.y=\(p2.y)")
//p2.x = 3 // can‘t change p2.x, since p2.x is a constant.

下面给出代码,说明引用类型:

class Point3 {
    var x = 0
    var y = 0
    let plet: Point4
    var pvar: Point4
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
        self.plet = Point4() // plet.x = 0, plet.y = 0
        self.pvar = Point4() // pvar.x = 0, pvar.y = 0
    }

    func moveToX(x: Int, andY y: Int) { // no need to use "mutating" keyword.
        self.x = x;
        self.y = y;
    }
}

class Point4 {
    var x = 0
    var y = 0
}

let p3 = Point3(x:1, y:2) // you can use let, even though you want to change the property, because it is a reference.
p3.x = 2
p3.moveToX(5, andY: 5) // no need to use the "mutating" keyword.
println("p3.x = \(p3.x), p3.y = \(p3.y)") // x = 5, y = 5

var p4 = p3 // p3 and p4 are the same, since they are reference type.
p4.x = 3
println("p4.x = \(p4.x), p4.y = \(p4.y)") // p4.x = 3, p4.y = 5
println("p3.x = \(p3.x), p3.y = \(p3.y)") // p3.x = 3, p3.y = 5

/**********************/
p3.plet.x = 4
println("p4.p.x = \(p3.plet.x), p4.p.y = \(p3.plet.y)") // p3.plet.x = 4, p3.plet.y = 0

let p5  = Point4()
//p3.plet = p5 // can‘t assign new value to p3.plet since the realtion can‘t change since the p property of p3 is a constant.
p3.pvar = p5 // even p3 is a constant, its propery can change.

在上面的代码中,最重要的就是"*"号以下的代码,可以说明引用类型中的let和var的作用。

更详细讨论,可以查看:http://stackoverflow.com/questions/24035648/swift-and-mutating-struct

Swift——(六)Swift中的值类型

时间: 2024-10-23 00:57:03

Swift——(六)Swift中的值类型的相关文章

【C#学习路途之一】数据类型中的值类型

刚刚学习了C#的数据类型中的值类型,在C#中,数据类型分为三中,一种是值类型,另一种是引用类型,最后一种不常用,是指针类型,这个在C语言中经常使用,到现在我都没搞明白! 整数类型: 数据类型 含义 取值范围 sbyte 有符号8位整数 -128到127 byte 无符号8位整数 0到255 short 有符号16位整数 -32768到32767 ushort 无符号16位整数 0到65535 int常用 有符号32位整数 2三十一次方 到 2三十一次方-1 uint 无符号32位整数 0到429

C#中的值类型与引用类型

这些天学习C#,看到里面的值类型与引用类型,例如结构是值类型,类是引用类型,然后立马想到了C++中的类,那么C++中的类是什么类型呢,哈哈,忽然间有点迷惑,上网搜了搜还真有很多小伙伴们已经晕进去了,今天就总结一下C#与C++中值类型与引用类型的区别. 其实C#中值类型与引用类型的根本区别就是变量包含的数据在哪个内存区间上,值类型在堆栈中直接包含,引用类型在堆中间接引用,例如,C#中实例化类必需要下面的语法: Class name = newclass(); 很容易看出来,类是在堆中分配的空间,然

JavaScript中的值类型和引用类型

先抛出一个题目,阿里的笔试面试题(很基础,但确实是阿里的笔试题) var a = {"x": 1}; var b = a; a.x = 2; a = {"x": 3}; console.log(b.x); 大家觉得最后在控制台输出的结果是多少? 如果你答案是2,那你就没必要接下去看了.如果不是.那你就接着看下去来解决你的疑惑吧! JavaScript中的值类型和引用类型 在javascript里面有两种变量类型,一种是值类型,一种是引用类型. 值类型:数值.布尔型.

探索C#中的值类型和引用类型

记得大三上学期上C#课程的时候,老师第一堂课就重点给我们讲了一下C#中的数据类型.我们都知道,C#是一门强类型的高级编程语言,了解它的数据类型是非常有必要的.老师当时给我们列举了很多数据类型,然后问我们哪些是值类型,那些是引用类型.说实话,当时对于这个问题还真是回答不上来,或许可以说是自己没有多少底气回答.虽然大一学C++的时候接触过值类型和引用类型,但是因为没有深究,或者根本没有真正了解他们的区别,以至于在自己写代码时无形当中用到了却还是不了解它们之间的具体区别. 现在大四了,也到了快紧张面试

C# 中的值类型和引用类型

原文 C# 中的值类型和引用类型 值类型(value type):int,long,float,double,decimal,char,bool 和 struct 统称为值类型.值类型变量声明后,不管是否已经赋值,编译器为其分配内存. 引用类型(reference type):string 和 class统称为引用类型.当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间.当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的

C#中对值类型和引用类型的一点认识

区别值类型和引用类型的重要一点就是值类型赋值的时候是给出一块内存空间,空间里放下要赋给值类型的值.而引用类型是开辟一块内存空间,空间里放下的是要赋给引用类型值的指向地址. 就像一个是复制了银行卡里的现金,你花了你复制的现金,和该银行卡是没有关系的.而引用类型是复制了一个银行卡,此卡为银行卡的副卡,因为他们的指向地址是一样的,所以当你使用副卡 的时候,主卡里的钱也会随之变动. 下面给出一段代码. using System; using System.Collections.Generic; usi

浅谈C#中的值类型和引用类型

在C#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为.如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常.很多人就是因为没有弄清楚这两个概念从而在编程过程中遇到了很多问题,在这里博主浅谈对值类型和引用类型的认识. 首先从概念上看,值类型直接存储其值,而引用类型存储对其值的引用.从而这两种类型存储在内存的不同地方. 其次从内存空间上看,值类型是在栈中操作,而引用类型则在堆中分配存储单元. 栈在编译的时候就分配好内存空间,在代码中有栈的

【.Net】浅谈C#中的值类型和引用类型

在C#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为.如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常.很多人就是因为没有弄清楚这两个概念从而在编程过程中遇到了很多问题,在这里博主浅谈对值类型和引用类型的认识. 首先从概念上看,值类型直接存储其值,而引用类型存储对其值的引用.从而这两种类型存储在内存的不同地方. 其次从内存空间上看,值类型是在栈中操作,而引用类型则在堆中分配存储单元. 栈在编译的时候就分配好内存空间,在代码中有栈的

Swift 中的值类型与引用类型

顶级修饰 次级修饰 赋值类型 存储类型 值类型 值类型   深拷贝 栈 值类型 引用类型 浅拷贝 堆 引用类型 值类型 浅拷贝 堆 引用类型 引用类型 浅拷贝 堆 复合引用类型会改变内部值类型的存储行为. 以上内容为推测 原文地址:https://www.cnblogs.com/feng9exe/p/9679909.html