sol2 二 教程:快速入门

断言 / 先决条件

你需要在代码中包含 #include <sol/sol.hpp> ,这只是一个头文件,不需要编译,但是你的lua 必须是编译可用的。

 

断言如下:

#ifndef EXAMPLES_ASSERT_HPP
#define EXAMPLES_ASSERT_HPP

#   define m_assert(condition, message) \
    do { \
        if (! (condition)) { \
            std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \
                      << " line " << __LINE__ << ": " << message << std::endl; \
            std::terminate(); \
        } \
    } while (false)

#   define c_assert(condition) \
    do { \
        if (! (condition)) { \
            std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \
                      << " line " << __LINE__ << std::endl; \
            std::terminate(); \
        } \
    } while (false)
#else
#   define m_assert(condition, message) do { if (false) { (void)(condition); (void)sizeof(message); } } while (false)
#   define c_assert(condition) do { if (false) { (void)(condition); } } while (false)
#endif

#endif // EXAMPLES_ASSERT_HPP

下面是在代码中快速使用断言

先打开一个lua state

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>
#include <assert.hpp>

int main(int, char*[]) {
	std::cout << "=== 打开 a state ===" << std::endl;

	sol::state lua;
	// open some common libraries 加载必要的库
	lua.open_libraries(sol::lib::base, sol::lib::package); 
	lua.script("print('bark bark bark!')"); //直接执行字符串脚本

	std::cout << std::endl;

	return 0;
}

在lua_state 中 使用 sol2 3.2

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>

int use_sol2(lua_State* L) {
	sol::state_view lua(L);
	lua.script("print('bark bark bark!')");
	return 0;
}

int main(int, char*[]) {
	std::cout << "=== 打开 sol::state_view on raw Lua ===" << std::endl;

	lua_State* L = luaL_newstate();
	luaL_openlibs(L);

	lua_pushcclosure(L, &use_sol2, 0);
	lua_setglobal(L, "use_sol2");

	if (luaL_dostring(L, "use_sol2()")) {
		lua_error(L);
		return -1;
	}

	std::cout << std::endl;

	return 0;
}

运行lua代码

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <fstream>
#include <iostream>
#include <assert.hpp>

int main(int, char*[]) {
	std::cout << "=== running lua code ===" << std::endl;

	sol::state lua;
	lua.open_libraries(sol::lib::base);
	
	// load and execute from string 执行lua中的 a = test
	lua.script("a = 'test'");
	// load and execute from file
	lua.script_file("a_lua_script.lua");

	// run a script, get the result
	int value = lua.script("return 54");
	c_assert(value == 54);

要运行Lua代码但有一个错误处理程序以防出错,请执行以下操作:

auto bad_code_result = lua.script("123 herp.derp", [](lua_State*, sol::protected_function_result pfr) {
		// pfr will contain things that went wrong, for either loading or executing the script
		// Can throw your own custom error
		// You can also just return it, and let the call-site handle the error if necessary.
		return pfr;
	});
	// it did not work
	c_assert(!bad_code_result.valid());
	
	// the default handler panics or throws, depending on your settings
	// uncomment for explosions:
	//auto bad_code_result_2 = lua.script("bad.code", &sol::script_default_on_error);
	return 0;
}

通过使用  .safe_script 脚本,您可以看到更多安全性的使用,该脚本返回一个受保护的结果,您可以使用该结果来正确检查错误和类似情况。

 

运行lua代码(低级)

您可以使用单个 load 和 function 执行操作符来加载、检查代码,然后运行和检查代码。

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <fstream>
#include <iostream>
#include <cstdio>
#include <assert.hpp>

int main(int, char*[]) {
	std::cout << "=== 运行 lua code (low level) ===" << std::endl;

	sol::state lua;                        //本地 state
	lua.open_libraries(sol::lib::base);    //加载基础库

	// load file without execute  加载lua文件,并执行
	sol::load_result script1 = lua.load_file("a_lua_script.lua");
	//execute
	script1();

	// load string without execute 加载字符串并执行
	sol::load_result script2 = lua.load("a = 'test'");
	//execute
	sol::protected_function_result script2result = script2();
	// optionally, check if it worked  检查返回的结果
	if (script2result.valid()) {
		// yay!
	}
	else {
		// aww
	}

	sol::load_result script3 = lua.load("return 24");
	// execute, get return value
	int value2 = script3();
	c_assert(value2 == 24);

	return 0;
}

 

向 lua 传递参数

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>
#include <assert.hpp>

int main(int, char* []) {
	std::cout << "=== 向 lua 传递 参数 ===" << std::endl;

	sol::state lua;
	lua.open_libraries(sol::lib::base);

	const auto& my_script = R"(
local a,b,c = ...
print(a,b,c)
	)";  //构建一个字符串

	sol::load_result fx = lua.load(my_script);//加载
	if (!fx.valid()) {
		sol::error err = fx;
		std::cerr << "failed to load string-based script into the program" << err.what() << std::endl;
	}
	
	// prints "your arguments here" 执行,并传入参数
	fx("your", "arguments", "here");

	return 0;
}

传递函数(转储字节码)

您可以转储函数的字节码,这允许您将其传输到另一个状态(或保存或加载)。请注意,字节码通常特定于Lua版本!

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>
#include "assert.hpp"


int main() {
	std::cout << "=== dump (serialize between states) ===" << std::endl;

	// 2 states, transferring function from 1 to another
	sol::state lua;  //lua state 1
	sol::state lua2;  //lua state 2

	// we're not going to run the code on the first
	// state, so we only actually need
	// the base lib on the second state
	// (where we will run the serialized bytecode)
	lua2.open_libraries(sol::lib::base);

	// load this code (but do not run)  state 1 加载函数字符串
	sol::load_result lr = lua.load("a = function (v) print(v) return v end");
	// check if it's sucessfully loaded
	c_assert(lr.valid());

	// turn it into a function, then dump the bytecode  得到 state 1 的函数信息,字节码
	sol::protected_function target = lr.get<sol::protected_function>();
	sol::bytecode target_bc = target.dump();

	// reload the byte code
	// in the SECOND state state 2将函数字节码view化后重新加载
	auto result2 = lua2.safe_script(target_bc.as_string_view(), sol::script_pass_on_error);
	// check if it was done properly
	c_assert(result2.valid());

	// check in the second state if it was valid state 2 执行函数a,传入参数,并检查结果
	sol::protected_function pf = lua2["a"];
	int v = pf(25557);
	c_assert(v == 25557);

	return 0;
}

设置和获取变量

您可以使用 set/get 语法来 设置/获取 所有内容。

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>

int main(int, char*[]) {
	sol::state lua;
	lua.open_libraries(sol::lib::base);

	// integer types 设置一个变量 
	lua.set("number", 24);
	// floating point numbers 设置变量2
	lua["number2"] = 24.5;
	// string types 设置字符串
	lua["important_string"] = "woof woof";
	// is callable, therefore gets stored as a function that can be called 设置一个函数
	lua["a_function"] = []() { return 100; };
	// make a table 设置一个表
	lua["some_table"] = lua.create_table_with("value", 24);

上面的设置和下面效果一样

// equivalent to this code
	std::string equivalent_code = R"(
		t = {
			number = 24,
			number2 = 24.5,
			important_string = "woof woof",
			a_function = function () return 100 end,
			some_table = { value = 24 }
		}
	)";

	// check in Lua
	lua.script(equivalent_code);

你可以证明它们是等价的:

lua.script(R"(
		assert(t.number == number)
		assert(t.number2 == number2)
		assert(t.important_string == important_string)
		assert(t.a_function() == a_function())
		assert(t.some_table.value == some_table.value)
	)");

使用以下语法检索这些变量:

// implicit conversion  直接获取变量
	int number = lua["number"];
	c_assert(number == 24);
	// explicit get 获取double类型变量
	auto number2 = lua.get<double>("number2");
	c_assert(number2 == 24.5);
	// strings too 获取字符串
	std::string important_string = lua["important_string"];
	c_assert(important_string == "woof woof");
	// dig into a table 获取表中的数据
	int value = lua["some_table"]["value"];
	c_assert(value == 24);
	// get a function 获取函数
	sol::function a_function = lua["a_function"];
	int value_is_100 = a_function();
	// convertible to std::function
	std::function<int()> a_std_function = a_function;
	int value_is_still_100 = a_std_function();
	c_assert(value_is_100 == 100);
	c_assert(value_is_still_100 == 100);

使用 object 和 sol:: 类型检索Lua类型。

sol::object number_obj = lua.get<sol::object>("number");
	// sol::type::number 获取number变量的类型
	sol::type t1 = number_obj.get_type();
	c_assert(t1 == sol::type::number);

	sol::object function_obj = lua["a_function"];
	// sol::type::function  获取变量的类型
	sol::type t2 = function_obj.get_type();
	c_assert(t2 == sol::type::function);
	bool is_it_really = function_obj.is<std::function<int()>>(); //检车函数的类型
	c_assert(is_it_really);

	// will not contain data
	sol::optional<int> check_for_me = lua["a_function"];
	c_assert(check_for_me == sol::nullopt);

	return 0;
}

您可以通过将其设置为 nullptr 或sol::lua  nil来擦除内容。

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>

int main(int, char*[]) {
	sol::state lua;
	lua.open_libraries(sol::lib::base);

	lua.script("exists = 250");

	int first_try = lua.get_or("exists", 322);
	c_assert(first_try == 250);

	lua.set("exists", sol::lua_nil);
	int second_try = lua.get_or("exists", 322);
	c_assert(second_try == 322);

	return 0;
}

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>

int main(int, char*[]) {

	sol::state lua;
	lua.open_libraries(sol::lib::base);

	lua.script(R"(
		abc = { [0] = 24 }
		def = { 
			ghi = { 
				bark = 50, 
				woof = abc 
			} 
		}
	)");

	sol::table abc = lua["abc"];
	sol::table def = lua["def"];
	sol::table ghi = lua["def"]["ghi"];

	int bark1 = def["ghi"]["bark"];
	int bark2 = lua["def"]["ghi"]["bark"];
	c_assert(bark1 == 50);
	c_assert(bark2 == 50);

	int abcval1 = abc[0];
	int abcval2 = ghi["woof"][0];
	c_assert(abcval1 == 24);
	c_assert(abcval2 == 24);

构建 表

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>

int main(int, char* []) {
	sol::state lua;
	lua.open_libraries(sol::lib::base);

	lua["abc_sol2"] = lua.create_table_with(
		0, 24
	); //直接创建一个表

	sol::table inner_table = lua.create_table_with("bark", 50,
		// can reference other existing stuff too
		"woof", lua["abc_sol2"]
	); 
	lua.create_named_table("def_sol2",
		"ghi", inner_table
	);//在已经存在的表中插入变量

检查一下

std::string code = R"(
		abc = { [0] = 24 }
		def = {
			ghi = {
				bark = 50,
				woof = abc
			}
		}
	)";

	lua.script(code);
	lua.script(R"(
		assert(abc_sol2[0] == abc[0])
		assert(def_sol2.ghi.bark == def.ghi.bark)
	)");

	return 0;
}

函数

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>

int main(int, char*[]) {
	sol::state lua;
	lua.open_libraries(sol::lib::base);

	lua.script("function f (a, b, c, d) return 1 end");
	lua.script("function g (a, b) return a + b end");

	// sol::function is often easier: 
	// takes a variable number/types of arguments...
	sol::function fx = lua["f"];
	// fixed signature std::function<...>
	// can be used to tie a sol::function down
	std::function<int(int, double, int, std::string)> stdfx = fx;

	int is_one = stdfx(1, 34.5, 3, "bark");
	c_assert(is_one == 1);
	int is_also_one = fx(1, "boop", 3, "bark");
	c_assert(is_also_one == 1);

	// call through operator[]
	int is_three = lua["g"](1, 2);
	c_assert(is_three == 3);
	double is_4_8 = lua["g"](2.4, 2.4);
	c_assert(is_4_8 == 4.8);

	return 0;
}

函数 绑定

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>
#include <iostream>

void some_function() {
	std::cout << "some function!" << std::endl;
}

void some_other_function() {
	std::cout << "some other function!" << std::endl;
}

struct some_class {
	int variable = 30;

	double member_function() {
		return 24.5;
	}
};

int main(int, char*[]) {
	std::cout << "=== functions (all) ===" << std::endl;
	
	sol::state lua;
	lua.open_libraries(sol::lib::base);

	// put an instance of "some_class" into lua
	// (we'll go into more detail about this later
	// just know here that it works and is
	// put into lua as a userdata
	lua.set("sc", some_class());

	// binds a plain function
	lua["f1"] = some_function;
	lua.set_function("f2", &some_other_function);

	// binds just the member function
	lua["m1"] = &some_class::member_function;

	// binds the class to the type
	lua.set_function("m2", &some_class::member_function, some_class{});

	// binds just the member variable as a function
	lua["v1"] = &some_class::variable;

	// binds class with member variable as function
	lua.set_function("v2", &some_class::variable, some_class{});

下面是调用这些的代码

lua.script(R"(
	f1() -- some function!
	f2() -- some other function!
	
	-- need class instance if you don't bind it with the function
    --需要类实例
	print(m1(sc)) -- 24.5
	-- does not need class instance: was bound to lua with one 
	print(m2()) -- 24.5 这个不需要
	
	-- need class instance if you 
	-- don't bind it with the function
	print(v1(sc)) -- 30
	-- does not need class instance: 
	-- it was bound with one 
	print(v2()) -- 30

	-- can set, still 
	-- requires instance
	v1(sc, 212)
	-- can set, does not need 
	-- class instance: was bound with one 
	v2(254)

	print(v1(sc)) -- 212
	print(v2()) -- 254
	)");

	std::cout << std::endl;

	return 0;
}

您可以使用sol::readonly(&some_class::variable)将变量设为只读,如果有人试图对其进行写入,则会出错。

self call

您可以通过C++传递自变量来模拟Lua中的“成员函数”调用。

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>

int main() {
	std::cout << "=== self_call ===" << std::endl;

	sol::state lua;
	lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table);

	// a small script using 'self' syntax
	lua.script(R"(
	some_table = { some_val = 100 }

	function some_table:add_to_some_val(value)
	    self.some_val = self.some_val + value
	end

	function print_some_val()
	    print("some_table.some_val = " .. some_table.some_val)
	end
	)");

	// do some printing
	lua["print_some_val"]();
	// 100

	sol::table self = lua["some_table"];
	self["add_to_some_val"](self, 10);
	lua["print_some_val"]();

	std::cout << std::endl;

	return 0;
}

lua 返回多个值

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>

int main(int, char* []) {
	sol::state lua;

	lua.script("function f (a, b, c) return a, b, c end");

	std::tuple<int, int, int> result;
	result = lua["f"](100, 200, 300);
	// result == { 100, 200, 300 }
	int a;
	int b;
	std::string c;
	sol::tie(a, b, c) = lua["f"](100, 200, "bark");
	c_assert(a == 100);
	c_assert(b == 200);
	c_assert(c == "bark");

	return 0;
}

返回多个值到lua

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>

int main(int, char* []) {
	sol::state lua;
	lua.open_libraries(sol::lib::base);

	lua["f"] = [](int a, int b, sol::object c) {
		// sol::object can be anything here: just pass it through
		return std::make_tuple(a, b, c);
	};

	std::tuple<int, int, int> result = lua["f"](100, 200, 300);
	const std::tuple<int, int, int> expected(100, 200, 300);
	c_assert(result == expected);

	std::tuple<int, int, std::string> result2;
	result2 = lua["f"](100, 200, "BARK BARK BARK!");
	const std::tuple<int, int, std::string> expected2(100, 200, "BARK BARK BARK!");
	c_assert(result2 == expected2);

	int a, b;
	std::string c;
	sol::tie(a, b, c) = lua["f"](100, 200, "bark");
	c_assert(a == 100);
	c_assert(b == 200);
	c_assert(c == "bark");

	lua.script(R"(
		a, b, c = f(150, 250, "woofbark")
		assert(a == 150)
		assert(b == 250)
		assert(c == "woofbark")
	)");

	return 0;
}

C++ classes from C++

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>
#include <iostream>

struct Doge {
	int tailwag = 50;

	Doge() {
	}

	Doge(int wags)
	: tailwag(wags) {
	}

	~Doge() {
		std::cout << "Dog at " << this << " is being destroyed..." << std::endl;
	}
};

int main(int, char* []) {
	std::cout << "=== userdata ===" << std::endl;

	sol::state lua;

	Doge dog{ 30 };

	// fresh one put into Lua
	lua["dog"] = Doge{};
	// Copy into lua: destroyed by Lua VM during garbage collection
	lua["dog_copy"] = dog;
	// OR: move semantics - will call move constructor if present instead
	// Again, owned by Lua
	lua["dog_move"] = std::move(dog);
	lua["dog_unique_ptr"] = std::make_unique<Doge>(25); //引用计数
	lua["dog_shared_ptr"] = std::make_shared<Doge>(31); //引用计数

	// Identical to above
	Doge dog2{ 30 };
	lua.set("dog2", Doge{});
	lua.set("dog2_copy", dog2);
	lua.set("dog2_move", std::move(dog2));
	lua.set("dog2_unique_ptr", std::unique_ptr<Doge>(new Doge(25)));
	lua.set("dog2_shared_ptr", std::shared_ptr<Doge>(new Doge(31)));

	// Note all of them can be retrieved the same way:
	Doge& lua_dog = lua["dog"];
	Doge& lua_dog_copy = lua["dog_copy"];
	Doge& lua_dog_move = lua["dog_move"];
	Doge& lua_dog_unique_ptr = lua["dog_unique_ptr"];
	Doge& lua_dog_shared_ptr = lua["dog_shared_ptr"];
	c_assert(lua_dog.tailwag == 50);
	c_assert(lua_dog_copy.tailwag == 30);
	c_assert(lua_dog_move.tailwag == 30);
	c_assert(lua_dog_unique_ptr.tailwag == 25);
	c_assert(lua_dog_shared_ptr.tailwag == 31);
	std::cout << std::endl;

	return 0;
}
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <assert.hpp>
#include <iostream>

struct Doge {
	int tailwag = 50;

	Doge() {
	}

	Doge(int wags)
		: tailwag(wags) {
	}

	~Doge() {
		std::cout << "Dog at " << this << " is being destroyed..." << std::endl;
	}
};

int main(int, char* []) {
	std::cout << "=== userdata memory reference ===" << std::endl;

	sol::state lua;
	lua.open_libraries(sol::lib::base);

	Doge dog{}; // Kept alive somehow

	// Later...
	// The following stores a reference, and does not copy/move
	// lifetime is same as dog in C++
	// (access after it is destroyed is bad)
	lua["dog"] = &dog;
	// Same as above: respects std::reference_wrapper
	lua["dog"] = std::ref(dog);
	// These two are identical to above
	lua.set( "dog", &dog );
	lua.set( "dog", std::ref( dog ) );


	Doge& dog_ref = lua["dog"]; // References Lua memory 引用lua内存
	Doge* dog_pointer = lua["dog"]; // References Lua memory 引用lua内存
	Doge dog_copy = lua["dog"]; // Copies, will not affect lua 不会影响lua

您可以用与其他方法相同的方式检索用户数据。重要的是,请注意,您可以更改usertype变量的数据,如果您获得指针或引用,它将影响lua中的内容:

lua.new_usertype<Doge>("Doge",
		"tailwag", &Doge::tailwag
	);

	dog_copy.tailwag = 525;
	// Still 50
	lua.script("assert(dog.tailwag == 50)");

	dog_ref.tailwag = 100;
	// Now 100
	lua.script("assert(dog.tailwag == 100)");

	dog_pointer->tailwag = 345;
	// Now 345
	lua.script("assert(dog.tailwag == 345)");

	std::cout << std::endl;

	return 0;
}

C++类进入Lua

您可以通过在注册枚举或用户类型之前创建一个表并为其指定所需的命名空间名称来模拟命名空间:

#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>
#include <assert.hpp>

int main() {
	std::cout << "=== namespacing ===" << std::endl;

	struct my_class {
		int b = 24;

		int f() const {
			return 24;
		}

		void g() {
			++b;
		}
	};

	sol::state lua;
	lua.open_libraries();

	// "bark" namespacing in Lua
	// namespacing is just putting things in a table
	// forces creation if it does not exist
	auto bark = lua["bark"].get_or_create<sol::table>();
	// equivalent-ish:
	//sol::table bark = lua["bark"].force(); // forces table creation
	// equivalent, and more flexible:
	//sol::table bark = lua["bark"].get_or_create<sol::table>(sol::new_table());
	// equivalent, but less efficient/ugly:
	//sol::table bark = lua["bark"] = lua.get_or("bark", lua.create_table());
	bark.new_usertype<my_class>("my_class",
		"f", &my_class::f,
		"g", &my_class::g); // the usual

	// can add functions, as well (just like the global table)
	bark.set_function("print_my_class", [](my_class& self) { std::cout << "my_class { b: " << self.b << " }" << std::endl; });

	// this works
	lua.script("obj = bark.my_class.new()");
	lua.script("obj:g()");

	// calling this function also works
	lua.script("bark.print_my_class(obj)");
	my_class& obj = lua["obj"];
	c_assert(obj.b == 25);

	std::cout << std::endl;

	return 0;
}

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值