句柄是一种可以保存对对象的引用的类型
使用句柄可以声明多个引用同一物理对象的变量
大部分情况下,你可以将其视作某种指针变量
使用方法
哪些对象有句柄
基本数据类型(bool
,int
,float
等)都不能具有句柄
注册类型时标记为不允许拥有句柄的类型也不能有句柄
声明句柄
通过在变量类型后加@符号来声明一个句柄
object@ jubing;
这样就可以声明一个句柄
句柄在声明时默认赋值为null
,即这个句柄没有引用任何对象
使用句柄
使用句柄和使用物理变量的方法一致,但是句柄无法保证已经引用了变量(句柄可能为null
),从而引起程序抛出异常,所以在使用句柄之前切记进行判断,或者你可以保证这个句柄永远不为空
//这将声明一个物理对象
object obj;
//这将声明一个句柄
object@ objHandle;
//两个方法作用完全相同
//均调用obj.Add()
obj.Add();
objHandle.Add();
//但是objHandle可能为空,因此最好进行判断
if(objHandle is null)
{
//balbalba
}
else
{
objHandle.Add();
}
句柄赋值
当句柄对象直接赋值时,他将指向所引用的对象
CApple apple;
//要操作实际的句柄对象,应该在表达式前加上@
CApple@ handle = @apple;
handle = apple;
//该式完全等同于
apple = apple;
//当句柄引用对象为空,将抛出异常
CApple@ badHandle;
badHandle = apple;
部分情况下,解释器可以隐式确定需要的是对象句柄,而不是句柄的本身,此时可以不在表达式前添加@
句柄比较
句柄间比较可以使用is
和!is
关键词来比较两个句柄是否指向同一个引用对象
CApple@ badApple;
CApple@ goodApple;
if(badApple is goodApple)
{
//balabalabala
}
//同时可以使用null关键词来验证句柄指向是否为空
if(badApple is null)
{
//kill it!
}
当使用==
和!=
运算符进行比较时,将使用opEquals运算符比较句柄所引用的对象
CPear metaPear;
CPear betaPear;
CPear@ aPear = @metaPear;
CPear@ bPear = @betaPear;
if(aPear == bPear)
{
//此式完全等同于if(metaPear == betaPear)
}
但是在变量前加上@,将视作is
和!is
if(@aPear != @bPear)
{
//将比较两个句柄是否指向同一个对象
}
句柄对象寿命
对象的生存期通常是在声明该变量所在的作用域期间
但是如果一个作用域外的句柄保留了对对象的引用,那么将会一直维持对象的存在,直到所有引用了该对象的句柄均释放时才会释放该对象
因此,对句柄的引用因慎重,以防内存泄露问题
object@ objHandle;
void Something()
{
object obj;
//通常情况下,在这个代码块结束时便释放obj
//但此时一个作用域外的句柄引用了该对象,该对象便保持存在
@objHandle = @obj;
}
//句柄释放了对对象的引用,此时obj才会被系统释放
@objHanle = null;
句柄对象关系和多态
通过继承或接口,可以使用对象句柄为相关类型编写通用代码
接口的句柄将可以储存所有使用了该接口的对象类型的引用
同样,父类的句柄将可以储存所有继承了父类的子类的引用
interface IChicken
{
void Walk();
}
class CHen : IChicken
{
void Walk() {}
void Lay() {}
}
class CCock : IChicken
{
void Walk() {}
void Crow() {}
}
//可以储存所有使用了接口的类引用
IChicken@ chickenHandle;
@chickenHandle = CHen();
@chickenHandle = CCock();
//继承类也如此
class CEgg : CHen {};
@chickenHandle = CEgg();
void Spawn(IChicken @iHandle)
{
//可在接口句柄中直接调用由接口实现的函数
@iHandle.Walk();
//但是要调用使用了接口的类的函数需要对接口句柄进行显式转化
//注意此时iHandle并没有@标记,因为解释器已经将其隐式辨认为了句柄,而不是句柄引用的变量
CCock@ cockHandle = cast<CCock@>(iHandle);
//在此情况下,cockHandle有为空句柄的风险,因此需要进行空句柄判断
if(cockHandle !is null)
{
cockHandle.Crow();
}
}
常量句柄
有时需要使用一直保持引用而不被修改的句柄,在句柄前加上const
前缀即可
CApple@ rewritalbeApple;
const CApple@ stableApple;
不可修改对象的句柄既可以引用可修改对象,也可以引用不可修改对象
但是脚本不允许通过该句柄修改对象
也不允许将该句柄传递给另一个允许修改的句柄
另外可以在类型后添加后缀const
声明只读句柄
//这是一个可修改对象的只读句柄
CApple@ const readonlyApple;
//这是一个不可修改对象的只读句柄
const CApple@ const ironApple;
区别
句柄类型 | 能否重新分配句柄引用 | 能否通过句柄修改对象 | 能否将句柄传递给另一个允许修改的句柄 |
---|---|---|---|
不可修改对象的不只读句柄 | √ | × | × |
可修改对象的只读句柄 | × | √ | √ |
不可修改对象的只读句柄 | × | × | × |
也就是说,const object@
将保证句柄引用的对象不被修改,而object@ const
将保证句柄本身不被修改
什么时候使用句柄
- 对象本身过大或过于复杂,直接复制对象值会导致寄存器占用增加时
- 需要对象数据双向流通或单向流通时