【问题标题】:Convert std::string to v8::string and viceversa?将 std::string 转换为 v8::string 反之亦然?
【发布时间】:2020-07-08 22:48:59
【问题描述】:

我正在尝试用 C++ 创建我的第一个节点模块。我只是想做一个简单的 Hello 传递我的名字作为参数。我发现这种将参数转换为 v8::strings 的方法看起来很丑:

Local<String> name = String::NewFromUtf8(isolate, *v8::String::Utf8Value(args[0]->ToString()));

有没有人可以建议我做这种演员的简单方法?!我错过了什么吗?!

【问题讨论】:

  • 一个简单的解决方案是将其隐藏并封装在某个函数中。

标签: c++ node.js string casting v8


【解决方案1】:

较新版本的 v8 也需要隔离:

void Foo(const v8::FunctionCallbackInfo<v8::Value> &args)
{
  // from v8 to cpp
  v8::Isolate* isolate = args.GetIsolate();
  v8::String::Utf8Value str(isolate, args[0]);
  std::string cppStr(*str);

  // back to v8
  v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, cppStr.c_str(), v8::String::kNormalString);
}

【讨论】:

  • for //back to v8 我得到错误:error: no member named 'kNormalString' in 'v8::String'
  • 用cybafelo的解决方案解决
【解决方案2】:

适用于与std::stringNewFromUtf8Utf8Value 之间的转换。但是,对于您的示例,来回转换不是必需的(实际上效率很低),您可以简单地执行以下操作:

Local<String> name = args[0]->ToString();

【讨论】:

    【解决方案3】:

    好的,我在使用节点 12 和 v8 7.4.288 时遇到了很多麻烦。

    所有常见的东西都已被弃用,所以我启动了 gdb 来检查实际的现状。

    所以 - 我假设您首先从 Argument 读取字符串 - 一种明智的方式(我可以从文档和示例中找出而不会太痛苦的唯一方式)是:

    v8::Local<v8::String> fileName; 
    fileName = args[0].As<v8::String>();
    

    正确 - 现在您有了 v8 格式的“字符串”(如 v8::Local&lt;v8::string&gt;

    要访问 v8::string(以便任何当前的 v8::String 内容甚至有点用处) - 您需要像这样取消引用变量:

    *fileName // 现在是 v8::String - 你可以使用 WriteUtf8 等函数 - 你可以用它做的事情记录在这里:

    https://v8docs.nodesource.com/node-12.0/d2/db3/classv8_1_1_string.html

    您会看到 WriteUtf8 函数需要隔离参数和 char* 缓冲区 - 我只是在这里猜测我的最大字符串长度并创建一个快速 char 缓冲区来保存我认为有意义的任何内容:

    char* charFileName = new char[8192];
    

    现在我有足够的空间来存储一些 UTF 8 字符串 - 我通过调用 WriteUtf8 函数来做到这一点

    (*fileName)->WriteUtf8(isolate, charFileName);
    

    最后 - 我已经像这样在其他地方(在全局范围内)定义了我的 std::string

    static std::string stringFileName;
    

    所以 - 要将数据从 char* 获取到我的 std::string 我这样做:

    stringFileName.assign(charFileName);
    

    如果您愿意,也可以通过调用 std::string 构造函数并在构造函数中将 char* 传递给它来实现。

    我删除了我原来的 char* 进行清理,因为它不再需要了 - 当 std::string 超出范围时,它会自行清理 - 我不知道 v8 如何自行清理,老实说我不知道没关系。

    delete charFileName;
    

    终于 - v8::String 字符串变成可用的 std::string - 今天(2020 年)

    另外 - 如果你现在想在 std::string 和 V8::String 之间进行转换,你可能会做类似的事情 - 将 std::string 转换为 char*,创建一个 &lt;v8::Local&lt;v8::String&gt;&gt;,取消引用它 (*mylocalv8string)并在取消引用的 localv8string 上调用 NewFromUtf8 (isolate, char*)

    【讨论】:

    • 这是我在 2020 年从 char* 类型转换为 v8::Local<:string v13>v8::Local<v8::String> result; v8::MaybeLocal<v8::String> temp = String::NewFromUtf8(isolate, jsonOutput); temp.ToLocal(&result); args.GetReturnValue().Set(result);
    【解决方案4】:

    节点 > v13

    这是我如何从 char* 类型转换为类型

    v8::Local<v8::String>
    

    2020 中获取节点中的返回值 > v13

    v8::Isolate *isolate = info.GetIsolate();
    auto context = isolate->GetCurrentContext();
    v8::Local<v8::String> result; 
    v8::MaybeLocal<v8::String> temp = String::NewFromUtf8(isolate, jsonOutput);
    temp.ToLocal(&result); 
    args.GetReturnValue().Set(result);
    

    【讨论】:

    • 对我来说,这个版本仍然会在 node@12.16.2 中触发弃用警告。如果将 NewStringType::kNormal 作为参数添加到 NewFromUtf8,它就会消失:String::NewFromUtf8(isolate, matrixJson.dump().c_str(), NewStringType::kNormal);
    【解决方案5】:

    我建议为此创建包装器。您还必须检查您的本地句柄name,如果它不为空。较新的实现使用 MaybeLocal 句柄来确保检查任何结果。

    我做过的一些例子:

    /* Tool: JS execution has been terminated. */
    class TerminateEx : public exception {
    public:
        virtual const char* what() const throw()
        { return "JSBaseClass: Execution terminated"; };
    };
    
    /* Tool: Convert MaybeLocal<> to Local<>
     * Throws TerminateEx if the handle is empty (JS execution has been
     * terminated).
     */
    template<typename C>
    inline v8::Local<C>
    JSBaseClass::toLocalHandle(v8::MaybeLocal<C> handle)
    {
        if (handle.IsEmpty())
            throw TerminateEx();
        return handle.ToLocalChecked();
    }
    
    /* Tool: Create JS string*/
    inline
    v8::Local<v8::String>
    JSBaseClass::newJSString(v8::Isolate *isolate, const char *str)
    {
        return (toLocalHandle(
                    v8::String::NewFromUtf8(
                        isolate, str, v8::NewStringType::kNormal)));
    };
    
    /* Tool: Create JS string*/
    inline
    v8::Local<v8::String>
    JSBaseClass::newJSString(v8::Isolate *isolate, const string &str)
    {
        return newJSString(isolate, str.c_str());
    };
    
    /* Tool: Create JS string*/
    template<typename T>
    inline v8::Local<v8::String>
    JSBaseClass::newJSString(const T &info, const string &str)
    {
        return newJSString(info.GetIsolate(), str.c_str());
    };
    
    [...]
    
    /* Tool: Throw JS exception */
    template<typename T> inline void
    JSBaseClass::throwJSError(const T &info, const string &text)
    {
        info.GetIsolate()->ThrowException(
            v8::Exception::Error(newJSString(info, text.c_str())));
        info.GetReturnValue().SetUndefined();
        return;
    };
    
    [...]
    
    /* Tool: Get string from JS value. returns false if the conversion failed. */
    inline bool
    JSBaseClass::valueToString(
        const v8::Local<v8::Context> &context,
        const v8::Local<v8::Value> &value,
        string *str)
    {
        v8::String::Utf8Value utf8Str(
            toLocalHandle(value->ToString(context)));
        if (!*utf8Str)
            return false;
    
        *str = *utf8Str;
        return true;
    }
    

    然后像这样使用它:

    try {
        auto isolate = info.GetIsolate();
        auto context = isolate->GetCurrentContext();
    
        Local<Value> name = JSBaseClass::newJSString(info, "My Name");
    
        [...]
    
        string nameStr;
    
        if (!JSBaseClass::valueToString(context, name, &nameStr)) {
            JSBaseClass::throwJSError(info, "Not a string");
            return;
        }
        [...]
    }
    catch (JSBaseClass::TemplateEx) {
        return;
    }
    

    如果您使用较新版本的 V8,您应该避免使用已弃用的方法。当前的方法大多返回 MaybeLocal&lt;&gt; 句柄。

    【讨论】:

      【解决方案6】:

      你也可以试试这个方法

          void StringConversion(const FunctionCallbackInfo<Value>& args){
              Isolate* isolate = args.GetIsolate(); // isolate will isolate the whole process in new memory space; so that no other thread can make change onto it at the same time 
              v8::String::Utf8Value s(args[0]); // take the string arg and convert it to v8::string
              std::string str(*s); // take the v8::string convert it to c++ class string
              //convert back the **str** to v8::String, so that we can set and return it 
              Local<String> result= String::NewFromUtf8(isolate,str.c_str()); // c_str() will return a pointer to an array that contain null-terminator sequence  
              args.GetReturnValue().Set(result);
          }
      

      谢谢!!

      【讨论】:

      • 设置结果,error: no viable conversion from 'MaybeLocal&lt;v8::String&gt;' to 'v8::Local&lt;v8::String&gt;' 编辑:用cybafelo的解决方案解决
      • 这个 MaybeLocal 句柄需要通过调用 'ToLocalChecked()' 解析为 Local 句柄。如果它是“空”并且不包含任何内容,您将收到运行时错误,否则,它将被解析为本地句柄。
      猜你喜欢
      • 2015-01-03
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 2018-05-18
      • 1970-01-01
      • 2023-03-22
      • 2011-09-11
      • 1970-01-01
      相关资源
      最近更新 更多