一、值类型和引用类型概念
值(value)类型 :Unity中的vector3、quaternion是structs,它们是值。
引用(feference)类型 :Unity中的transform、gameobject是类类型,所以它们是引用。引用类型是对数据存储位置的引用,引用类型指向的内存区域称为堆。
在决定定义引用类型还是值类型时,关键因素是:如果逻辑上是固定大小不可变的值,就考虑定义成值类型,如果逻辑上是可引用的可变的对象,就定义成引用类型。例如字符串类型,它的大小是根据值的大小而改变的,所以它是引用类型。
所以哪些是值?哪些是引用?
0. int float bool等是值。
1. struct是值,class是引用
2. 数组是引用,即使元素是值类型(int[]是引用)
3. 枚举(enum)是值
4. 委托(delegate)是引用
5. 接口(interface)是引用,但可用值类型实现。
引用类型在堆上,值类型在栈上?
引用类型的实例总是在堆上的没有错,但是方法内部声明的变量和方法参数在栈上。 而且实例变量的值总是存储在实例本身存储的地方。例如如一个类中有个int变量,虽然它是一个值类型,但它在堆上。
引用类型的变量包含了两个存储位置:直接和变量关联的存储位置,以及由变量中存储的值引用的存储位置。
对于直接与变量关联的存储位置和值类型变量关联的存储位置,它们的存储位置没有区别,也就是引用本身会和值类型一样,如果一直变量短时间存在,就在栈的临时存储池中分配。
注意:不要创建消耗内存大于16字节的值类型,因为一个引用的大小就是32字节或64字节,如果复制值类型的代价比作为引用复制时高出四倍,就应该把它设计为引用类型了。
二、unity中的值类型和引用类型
首先看一组值类型和引用类型的比较:
Vector3:它在unity中被定义为一个结构体,它是一个值类型,如下所示,我们如果修改了pos,它不会和transform.position有任何关系,也就是这个物体的位置并不会改变;
Vector3 pos=transform.position; pos=Vector3.zero;
Mat:它是一个类类型,也就是引用类型,如下所示,如果修改了mat,那么这个物体的材质的颜色就真的被改变了;
Material mat=GetComponent<MeshRenderer>().material; mat.color=Color.red;
总结:我们在定义变量需要明白这个变量类型是值类型还是引用类型,如果是引用类型,它到底是指向什么的引用;
三、按值传递引用类型和按引用传递引用类型
我们已经介绍了一个引用类型的变量包括了两部分:它自身所存储的引用以及这个引用所指向的内存;
如果我们使用如下语句,那么引用类型所它自身所存储的引用就是指向当前物体的transform的;第二行代码,我们修改的tr所指向的内存中的变量的内容;但是接下来第三行代码,tr的引用指向了otherObj的transform,这里我们修改的不是tr指向的值,而是它自身所指向的引用;
Transform tr=this.transform; tr.position=Vector3.One; tr=otherObj.transform;
在unity中,有时候我们可能会传递一个引用变量,对于引用变量,一共有两种方式,按值传递和按引用传递;
如下是一个案例,我们设计了两个函数,分别是按值传递和按引用传递Transform,然后在函数里修改Transform,我们通过name来观察修改结果;在场景中将target和target2分别用cube1和cube2赋值,首先第一个log会是cube1,那么第二个log呢,我们就要在此了解一下两种传递方式的区别了;
按值传递:我们使用按值传递引用类型,就意味着我们只能通过传递参数来修改这个引用类型所引用的值,函数结束后修改值会被保存到参数中,但是不能修改这个引用类型本身所指向的引用,因为函数结束后这种修改并不会被保存到传入的引用类型变量中;
按引用传递:会修改传入的引用类型参数自身的引用;
所以,调用第一个按值传递时,我们执行的一句用于修改引用自身的代码在函数执行结束后就会失效,t并没有被修改;而第二个按引用传递,t本身就是被修改成了cube2的transform;
public Transform target; public Transform target2; void Start() { Debug.Log(target.name); ChangeTargetByVal(target); Debug.Log(target.name); ChangeTargetByRef(ref target); Debug.Log(target.name); } private void ChangeTargetByVal(Transform t) { t = target2.transform; } private void ChangeTargetByRef(ref Transform t) { t=target2.transform; }
发表评论 取消回复