我正在尝试用 C++ 创建我的第一个节点模块。我只想做一个简单的 Hello,将我的名字作为参数传递。我发现这种方法将参数转换为 v8::strings ,这看起来很丑陋:
Local<String> name = String::NewFromUtf8(isolate, *v8::String::Utf8Value(args[0]->ToString()));
有谁可以建议我简单的方法来进行这种演员阵容吗?!我是不是错过了什么?!
较新版本的 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);
}
对于
std::string
的转换,NewFromUtf8
和 Utf8Value
是合适的。然而,对于您的示例,来回转换是不必要的(事实上,效率很低),您可以简单地执行以下操作:
Local<String> name = args[0]->ToString();
好吧,我在使用节点 12 和 v8 7.4.288 时遇到了很多麻烦。
所有常用的东西都已被弃用,所以我启动了 gdb 来检查实际现状。
所以 - 我假设你首先从参数中读取字符串 - 一种明智的方法(我可以从文档和示例中找出没有太多痛苦的唯一方法)是这样的:
v8::Local<v8::String> fileName;
fileName = args[0].As<v8::String>();
对 - 现在你有了 v8 格式的“字符串”(如
v8::Local<v8::string>
)
要访问
v8::String
(因此任何当前的 v8::String
内容甚至稍微有用) - 您需要像这样取消引用变量:
*fileName
现在这是一个
v8::String
- 您可以使用 WriteUtf8
等功能 - 您可以用它做的事情记录在此处:
https://v8docs.nodesource.com/node-20.3/d2/db3/classv8_1_1_string.html
WriteUtf8
函数需要隔离参数和 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*
,创建一个 <v8::Local<v8::String>>
,取消引用它 (*mylocalv8string)
并调用 NewFromUtf8 (isolate, char*)
在取消引用的 localv8string 上。
这是我如何从 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);
我建议为此创建包装器。您还必须检查您的本地句柄
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<>
句柄。
你也可以尝试这个方法
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);
}
谢谢!!