Unity中的引用传递和值传递
有没有试过传递参数时明明修改了,但函数执行完毕后值却没有改变?这里需要搞清楚值类型数据和引用类型数据当作参数传递时的坑,简单来说值类型数据存储的是实际的数据,而引用类型顾名思义就是存储了实际数据的引用。这里先看看演示,struct为值类型,class为引用类型。
struct Item
{
public int id;
public string name;
}
void Start()
{
//实例化一个结构体,结构体为值类型数据
Item itemA = new Item();
itemA.id = 1;
itemA.name = "zzy";
Debug.Log(itemA.id + " " + itemA.name);
ChangeStruct(itemA);
Debug.Log(itemA.id + " " + itemA.name);
}
//改变参数中的数据
void ChangeStruct(Item item)
{
item.id = 10;
item.name = "zzzzzzzzzy";
Debug.Log(item.id + " " + item.name);
}
可以看到参数的数值确实变了,但原本的数值没有改变。
如果我们把Item设置为引用类型数据结果会如何?//将struct修改为class
可以看到参数的数值变了,原本的数值也变了。
C++无论传递的是什么类型的数据,默认都是值传递,而C#默认情况下传递值类型数据时用值传递,传递引用类型数据时用引用传递。
在值类型数据作为参数时会复制一份副本,而副本就是函数里使用的参数,函数修改的是副本的数据,自然对原本的数据没有影响。而引用类型作为参数时传递的是引用本身,修改参数就相当于修改自己。
对应到Unity的原生数据会出现什么情况呢?
[Header("自身Transform")]
[SerializeField] Transform selfTrans;
[Header("自身Vector")]
[SerializeField] Vector2 selfVec;
void Start()
{
selfVec = selfTrans.position;
ChangeStruct(selfVec);
}
void ChangeStruct(Vector2 vec)
{
vec = new Vector2(1, 1);
}
开始前:
开始后:
可以看到物体的位置并没有被改变,如果按住ctrl点击Vector2可以发现它是值类型的数据:
如果在代码中想要修改物体位置时修改物体的Vector变量,是毫无作用的,因为修改的Vector不是物体原本的Vector。
那如果修改物体的Transform呢?
[Header("自身Transform")]
[SerializeField] Transform selfTrans;
[Header("自身Vector")]
[SerializeField] Vector2 selfVec;
// Start is called before the first frame update
void Start()
{
ChangeClass(selfTrans);
}
void ChangeClass(Transform trans)
{
trans.position = new Vector2(1, 1);
}
可以看到物体位置确实发生了改变,因为Transform是引用类型数据,这点可以查看Transform父类进行查看,最高级的父类为Object类,Object为所有引用类型数据的基类。
那么如果想引用传递的方式传递值类型数据要怎么做呢?在C++中用到&或*标识符传递数据的引用或指针,而在C#中用到ref关键字。
void Start()
{
ChangeStruct(ref selfVec);
}
void ChangeStruct(ref Vector2 vec)
{
vec = new Vector2(1, 1);
}
开始前:
开始后:
可以看到原本的值也改变了,用ref关键字就能实现值类型数据的引用传递,搞清楚了这两种数据的区别才不会出现明明修改了数据最后却没有变化的BUG。
两种数据类型的详细区别请看此链接