作为全局对象的QScriptValue的深层副本

Dav*_*dia 5 c++ qt qtscript

我有一个程序使用QtScript进行一些自动化.我已经在脚本引擎的全局范围中添加了一堆C++函数和类,以便脚本可以访问它们,如下所示:

QScriptValue fun = engine->newFunction( systemFunc );
engine->globalObject().setProperty( "system", fun );
Run Code Online (Sandbox Code Playgroud)

我希望能够连续运行多个脚本,每个脚本都有一个全新的状态.因此,如果一个脚本设置了一个全局变量,比如

myGlobalVar = "stuff";
Run Code Online (Sandbox Code Playgroud)

我希望在下一个脚本运行之前擦除该变量.我这样做的方法是制作脚本引擎的全局对象的深层副本,然后在脚本完成运行时恢复它.但深拷贝不起作用,因为我的system功能突然出现错误:

TypeError: Result of expression 'system' [[object Object]] is not a function.
Run Code Online (Sandbox Code Playgroud)

这是我的深层复制功能,改编自:http:
//qt.gitorious.org/qt-labs/scxml/blobs/master/src/qscxml.cpp

QScriptValue copyObject( const QScriptValue& obj, QString level = "" )
{
    if( obj.isObject() || obj.isArray() ) {
        QScriptValue copy = obj.isArray() ? obj.engine()->newArray() : obj.engine()->newObject();
        copy.setData( obj.data() );
        QScriptValueIterator it(obj);
        while(it.hasNext()) {
            it.next();
            qDebug() << "copying" + level + "." + it.name();
            if( it.flags() & QScriptValue::SkipInEnumeration )
                 continue;
            copy.setProperty( it.name(), copyObject(it.value(), level + "." + it.name()) );
        }
        return copy;
    }

    return obj;
}
Run Code Online (Sandbox Code Playgroud)

(SkipInEnumeration被放入以避免无限循环)

编辑:我认为,部分问题是在调试器(QScriptEngineDebugger)中,我添加的函数和构造函数应该显示为类型Function,但在复制后,它们显示为类型Object.我还没有找到一种创建一个复制现有函数的新函数的好方法(QScriptEngine :: newFunction接受一个实际的函数指针).

Dav*_*dia 1

我成功了。这是解决方案,以防对其他人有用:

QScriptValue copyObject( const QScriptValue& obj)
{
    if( (obj.isObject() || obj.isArray()) && !obj.isFunction() ) {
        QScriptValue copy = obj.isArray() ? obj.engine()->newArray() : obj.engine()->newObject();
        copy.setData( obj.data() );
        QScriptValueIterator it(obj);
        while(it.hasNext()) {
            it.next();
            copy.setProperty( it.name(), copyObject(it.value()) );
        }
        return copy;
    }

    return obj;
}
Run Code Online (Sandbox Code Playgroud)

重要的部分是添加了检查!obj.isFunction(),它只会按原样复制函数,而不进行深层复制。这里的微妙之处在于,isObject()如果该项目是一个函数,它将返回 true,这是我们不想要的。这在 Qt 文档中有记录,我不久前偶然发现了它。

此外,此检查消除了避免复制标记为 的项目的需要SkipInEnumeration。通过检查函数并按原样复制它们来修复无限循环。离开实际上SkipInEnumeration破坏了其他一些东西,比如eval函数和一堆其他内置函数。