句柄是一种可以保存对对象的引用的类型
使用句柄可以声明多个引用同一物理对象的变量
大部分情况下,你可以将其视作某种指针变量


使用方法

哪些对象有句柄

基本数据类型(boolintfloat等)都不能具有句柄
注册类型时标记为不允许拥有句柄的类型也不能有句柄

声明句柄

通过在变量类型后加@符号来声明一个句柄

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将保证句柄本身不被修改

什么时候使用句柄

  • 对象本身过大或过于复杂,直接复制对象值会导致寄存器占用增加时
  • 需要对象数据双向流通或单向流通时
Categories: 教程合集

Dr.Abc

I ❤ Owl

订阅
提醒
guest

1 评论
最新
最旧 得票最多
Inline Feedbacks
View all comments
1
0
Would love your thoughts, please comment.x