当前位置: 首页 > article >正文

MoonSharp 文档一

目录

1.Getting Started

步骤1:在 IDE 中引入 MoonSharp

步骤2:引入命名空间

步骤3:调用脚本

步骤4:运行代码

2.Keeping a Script around

步骤1:复现前教程所有操作

步骤2:改为创建Script对象

步骤3:访问全局环境

步骤4:直接调用函数

3.DynValue revealed

步骤1:重新执行你在上一个教程中的所有操作

步骤2:将 fact 函数存入 DynValue

步骤3:将数字存入 DynValue

步骤 4:了解 DataType(s)

步骤 5:元组

4.Calling back C#

步骤 1:永远不要厌倦阶乘

步骤 2:自定义乘法函数

返回一系列数字

返回表格

接收一个表

5.Auto-conversions

自定义转换器

CLR 类型到 MoonSharp 类型的自动转换

MoonSharp 类型到 CLR 类型的标准自动转换

MoonSharp 类型到 CLR 类型的受限自动转换


文档地址:

MoonSharp

1.Getting Started

您的第一个 MoonSharp 项目的快速指南

本教程将带你初步体验 MoonSharp 的简洁与强大。虽然 MoonSharp 有更优的使用方式,但这是最基础的一种。其他教程会深入探讨如何充分发挥 MoonSharp 的潜力。现在,让我们开始吧!


关于语言支持的说明
本网站大多数教程仅提供 C# 示例,但本页会为 VB.NET 用户提供一些指引。
MoonSharp 兼容所有 CLR 语言(C#、VB.NET、C++/CLI、F#、Boo 等),理论上也支持DLR语言(如 IronPython、IronRuby)。但由于维护多语言示例的工作量较大,后续教程仅提供 C# 示例(本入门页含 VB.NET)。
大多数教程的代码可在 GitHub 的示例项目中找到。
学习前提:需熟悉Lua和至少一门.NET语言(推荐 C#),否则可能难以理解示例。


步骤1:在 IDE 中引入 MoonSharp

根据使用的IDE(Visual Studio、MonoDevelop、SharpDevelop、Unity)选择以下方式:

Visual Studio(通过 NuGet)
1.在包管理器控制台输入:

PM> Install-Package MoonSharp  

2.或右键“引用”->“管理NuGet包”->搜索“MoonSharp”并安装。

Xamarin Studio(通过NuGet)
菜单栏选择“项目”->“添加NuGet包”->搜索“MoonSharp”并安装。

其他IDE(手动添加)
将 MoonSharp 发行包中对应平台的 MoonSharp.Interpreter.dll 添加为项目依赖。

Unity
1.推荐方式:通过Asset Store安装(待审核后在此链接提供)。

2.手动方式:
将 interpreter/net35 目录下的 MoonSharp.Interpreter.dll 放入 Assets/Plugins。
若需支持 Windows Store/WP:
    将 interpreter/portable-net40 下的 DLL放入 Assets/Plugins/WSA。
    参考此指南配置。链接

3.IL2CPP项目:
在 Assets 目录下创建/编辑 link.xml,内容如下:

<linker>  <assembly fullname="MoonSharp.Interpreter">  <type fullname="MoonSharp.*" preserve="all" />  </assembly>  
</linker>  

步骤2:引入命名空间

在代码顶部添加:
C#

using MoonSharp.Interpreter;  

VB.NET

Imports MoonSharp.Interpreter  

步骤3:调用脚本

以下示例演示如何用MoonSharp计算阶乘:

C#

double MoonSharpFactorial()
{string script = @"    -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endendreturn fact(5)";DynValue res = Script.RunString(script);return res.Number;
}

VB.NET

Function MoonSharpFactorial() As Double' VB.NET is not very strong at embedded newlines...Dim scriptCode As String = "-- defines a factorial function" & vbCrLf &"function fact (n)" & vbCrLf & _"if (n == 0) then" & vbCrLf & _"return 1" & vbCrLf & _"else" & vbCrLf & _"return n*fact(n - 1)" & vbCrLf & _"end" & vbCrLf & _"end" & vbCrLf & _"return fact(5)" & vbCrLfDim res As DynValue = Script.RunString(scriptCode)Return res.Number
End Function

步骤4:运行代码

在代码中调用MoonSharpFactorial()即可执行脚本。现在,你可以继续探索其他教程了!
 

2.Keeping a Script around

言语易逝,文字永存。

在之前的教程中,你首次接触了 MoonSharp:将脚本放入字符串中运行并获取输出。虽然偶尔有用,但大多数实际用例需要的互操作性需要 CLR 代码与 MoonSharp 更深度的集成。

步骤1:复现前教程所有操作

认真地说,虽然我们在这里学习的是(稍微)更高级的概念,但你最初的尝试几乎无需改动。这正是一个极好的起点。

步骤2:改为创建Script对象

首先要做的更改是创建一个脚本对象,而不是使用静态方法之一。这并非什么难事,但它为我们接下来的发展奠定了基础。

double MoonSharpFactorial()
{string scriptCode = @"    -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endendreturn fact(5)";Script script = new Script();DynValue res = script.DoString(scriptCode);return res.Number;
}

步骤3:访问全局环境

现在有了脚本对象,我们可以修改函数运行的全局环境。例如,改变阶乘函数的输入参数,让程序能指定计算目标数值的阶乘。
 

double MoonSharpFactorial()
{string scriptCode = @"    -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endendreturn fact(mynumber)";Script script = new Script();script.Globals["mynumber"] = 7;DynValue res = script.DoString(scriptCode);return res.Number;
}

通过简单的 script.Globals 表引用语法,我们实现了向 MoonSharp 脚本注入数值。实际上不仅能传递数字,后续还将演示如何传递函数和对象,但现阶段我们暂限于数字、布尔值和字符串。

步骤4:直接调用函数

我们学习了如何让 MoonSharp 计算从外部选择的数字的阶乘。但是,以这种方式完成,感觉像是一个肮脏的黑客行为(尽管如此,这是一项重要的技术,我们将经常使用)。

下面是如何从C#调用Lua函数。

double MoonSharpFactorial2()
{string scriptCode = @"    -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endend";Script script = new Script();script.DoString(scriptCode);DynValue res = script.Call(script.Globals["fact"], 4);return res.Number;
}

我们来看看具体做了哪些调整。

首先,我们删除了脚本结尾的 return 语句——这个语句本来可以保留,但由于我们需要通过自定义参数调用 fact 函数,保留它反而会导致冗余。

此时,script.DoString(...)  的调用将会执行整个脚本文件,在全局环境中留下一个完整可用的 fact 函数。

随后我们添加了这一行代码:

DynValue res = script.Call(script.Globals["fact"], 4);

这段代码会从脚本的全局环境中获取 fact 函数,并以参数4进行调用。

虽然存在更高效的实现方式(特别是在性能方面),但如果您不需要在时间敏感的循环中进行大量调用,这无疑是最简单的解决方案(不过存在一定的类型安全隐患)。

值得注意的是,fact 函数可以任意次数被调用——因为 Script 会保留其运行状态,并随时准备好被反复执行。

3.DynValue revealed

一切皆是 DynValue,DynValue 即一切。

DynValue 概念实际上是 MoonSharp 的核心基础,尽管到目前为止我们几乎没有涉及太多,但事实上,想要深入了解而不触及这一主题是不太可能的。

如标题所述,MoonSharp 中的(几乎)所有内容都是 DynValue 对象的实例。一个 DynValue 代表脚本中的一个值,无论其类型如何,因此它可以是一个表、一个函数、一个数字、一个字符串或其他任何东西。

那么,让我们从最新的教程步骤开始,并将其改为使用 DynValue。

步骤1:重新执行你在上一个教程中的所有操作

我们再次从上一个教程的最后一步开始。你已经完成了吧?

你可以在这里获取参考文档。

步骤2:将 fact 函数存入 DynValue

第一个改动是我们以不同的方式获取 fact 变量:

double MoonSharpFactorial()
{string scriptCode = @"    -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endend";Script script = new Script();script.DoString(scriptCode);DynValue luaFactFunction = script.Globals.Get("fact");DynValue res = script.Call(luaFactFunction, 4);return res.Number;
}

好的,让我们在这一行花点时间:

DynValue luaFactFunction = script.Globals.Get("fact");

这样可以从脚本的全局作用域中获取 fact 函数。与索引器属性不同,「Get」方法会直接返回一个「DynValue」类型,而索引器则会尝试将其转换为「System.Object」。在本例中,由于我们需要获取的是「DynValue」类型,因此选择使用「Get」方法。

步骤3:将数字存入 DynValue

如果我们希望避免额外的类型转换,可以直接以「DynValue」形式传递数字,而无需依赖「Call」方法提供的隐式转换。虽然当前场景中这不是必需的,但在其他情况下可能会用到,毕竟并非所有操作都会自动帮你完成类型转换!

double MoonSharpFactorial2()
{string scriptCode = @"    -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n*fact(n - 1)endend";Script script = new Script();script.DoString(scriptCode);DynValue luaFactFunction = script.Globals.Get("fact");DynValue res = script.Call(luaFactFunction, DynValue.NewNumber(4));return res.Number;
}

所以,我们用以下内容替换了我们的数字:

DynValue.NewNumber(4)

DynValue 有许多工厂方法,都以 "New" 开头(如 NewString、NewNumber、NewBoolean 等),可用于从头开始构建我们的值。

它还有一个方便的 FromObject 方法,可以从对象创建 DynValue,这正是 Call 在幕后使用的方法,以简化我们的工作。

步骤 4:了解 DataType(s)

在 DynValue 中,最重要的属性之一是 Type。

Type 属性是一个枚举,告诉我们 DynValue 中包含了什么类型的数据。

每当我们想知道 DynValue 中包含了什么,我们都可以查询 Type 属性:

// Create a new number
DynValue v1 = DynValue.NewNumber(1);
// and a new string
DynValue v2 = DynValue.NewString("ciao");
// and another string using the automagic converters
DynValue v3 = DynValue.FromObject(new Script(), "hello");// This prints Number - String - String
Console.WriteLine("{0} - {1} - {2}", v1.Type, v2.Type, v3.Type);
// This prints Number - String - Some garbage number you shouldn't rely on to be 0
Console.WriteLine("{0} - {1} - {2}", v1.Number, v2.String, v3.Number);

重要的是要知道,DynValue 的某些属性只有在值是给定类型时才有意义。例如,只有当类型为 DataType.Number 时,Number 属性才能保证有意义的值,String 属性也是如此。

除非你确定 DynValue 包含什么,否则在使用其属性之前,请务必检查 DynValue 的 Type。假设 DynValue 包含一个给定类型,而它实际上包含另一个类型,这是错误和问题的常见来源。

步骤 5:元组

正如你(应该)知道的,Lua 可以从函数(以及其他情况)返回多个值。

为了处理这种情况,使用了一种特殊的 DynValue 类型(DataType.Tuple)。元组有一个 Tuple 属性,它是 DynValue 对象的数组,这些对象是元组的成员。

这比听起来更简单:

DynValue ret = Script.RunString("return true, 'ciao', 2*3");// prints "Tuple"
Console.WriteLine("{0}", ret.Type);// Prints:
//   Boolean = true
//   String = "ciao"
//   Number = 6
for (int i = 0; i < ret.Tuple.Length; i++)Console.WriteLine("{0} = {1}", ret.Tuple[i].Type, ret.Tuple[i]);

结语

关于 DynValue 的介绍就到这里。还有很多需要学习的内容,但这些应该足以让你入门了。

请记住这些内容,因为这是一切的核心。

4.Calling back C#

但也支持 F# 和 VB.NET 和 C++/CLI 和 Boo 等等...

脚本在应用程序中非常有用,因为它们可以从包含应用程序本身实现的构建块开始,自定义业务逻辑。无论您是在商业应用程序、视频游戏还是某种工具中嵌入脚本,您的首要关注点是脚本和应用程序的互操作性以及两者之间的对象共享(在某种意义上)。

而过程编程中的基本构建块是函数。

步骤 1:永远不要厌倦阶乘

让我们从到目前为止我们使用的标准阶乘脚本开始:

private static double CallbackTest()
{string scriptCode = @"    -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn n * fact(n - 1);endend";Script script = new Script();script.DoString(scriptCode);DynValue res = script.Call(script.Globals["fact"], 4);return res.Number;
}

步骤 2:自定义乘法函数

好的,假设我们希望乘法在宿主应用程序的 API 函数中实现。在这种情况下,这样做显然没有任何目的,但我们在这里是为了学习,所以让我们假装这是一个好主意。

private static int Mul(int a, int b)
{return a * b;
}private static double CallbackTest()
{string scriptCode = @"    -- defines a factorial functionfunction fact (n)if (n == 0) thenreturn 1elsereturn Mul(n, fact(n - 1));endend";Script script = new Script();script.Globals["Mul"] = (Func<int, int, int>)Mul;script.DoString(scriptCode);DynValue res = script.Call(script.Globals["fact"], 4);return res.Number;
}

就是这样!

script.Globals["Mul"] = (Func<int, int, int>)Mul;

这将全局环境中的 Mul 变量设置为指向应用程序的 Mul 委托。我们在这里将委托强制转换为它的 Func<int, int, int> 类型以取悦 C# 编译器 - 无论您使用什么技术将委托强制转换为 System.Object 都可以。

另外,请注意,我们将方法定义为静态的,但在这种情况下,它们完全不需要是静态的;实例方法也可以使用。

返回一系列数字

问题:有一个API函数,它返回一个整数序列。脚本将对收到的数字求和,并返回总数。

private static IEnumerable<int> GetNumbers()
{for (int i = 1; i <= 10; i++)yield return i;
}private static double EnumerableTest()
{string scriptCode = @"    total = 0;for i in getNumbers() dototal = total + i;endreturn total;";Script script = new Script();script.Globals["getNumbers"] = (Func<IEnumerable<int>>)GetNumbers;DynValue res = script.DoString(scriptCode);return res.Number;
}

在这里,也没有太难的地方。你可以看到如何将一个 IEnumerable(或 IEnumerator)即时转换为 Lua 迭代器,以便脚本运行。

还要注意,脚本中直接包含了可执行代码,因此在 DoString 时刻就可以访问 getNumbers 方法,无需进行 Call.. 调用。记住这一点,DoString 和 DoFile 将立即执行脚本中包含的代码!

还有一点必须注意。MoonSharp 能够转换 System.Collections.IEnumerable 和 System.Collections.IEnumerator 类型的迭代器。也就是说,非泛型的变体。如果由于某种原因你实现了一个泛型迭代器而没有实现非泛型迭代器,那么迭代器将无法工作。所有标准的集合类型和迭代器方法,如上面的方法,默认实现了非泛型变体,所以不需要太担心。

返回表格

问题:有一个API函数,这次返回一个整数序列,存储在一个表格中。

private static List<int> GetNumberList()
{List<int> lst = new List<int>();for (int i = 1; i <= 10; i++)lst.Add(i);return lst;
}private static double TableTest1()
{string scriptCode = @"    total = 0;tbl = getNumbers()for _, i in ipairs(tbl) dototal = total + i;endreturn total;";Script script = new Script();script.Globals["getNumbers"] = (Func<List<int>>)GetNumberList;DynValue res = script.DoString(scriptCode);return res.Number;
}

在这里,我们可以看到 List<int> 是如何自动转换为 Lua 表的!请注意,生成的表将像 Lua 表通常那样以1为索引。

然而,我们可以做得更好。我们可以直接在函数内部构建一个 Lua 表:

private static Table GetNumberTable(Script script)
{Table tbl = new Table(script);for (int i = 1; i <= 10; i++)tbl[i] = i;return tbl;
}private static double TableTest2()
{string scriptCode = @"    total = 0;tbl = getNumbers()for _, i in ipairs(tbl) dototal = total + i;endreturn total;";Script script = new Script();script.Globals["getNumbers"] = (Func<Script, Table>)(GetNumberTable);DynValue res = script.DoString(scriptCode);return res.Number;
}

您可以看到使用 Table 对象操作表是多么容易。

但是有两点需要注意:

要创建一个新的 Table 对象,您必须有一个对正在执行的脚本的引用
如果在 CLR 函数中有一个 Script 参数可供 Lua 脚本使用,MoonSharp 将为您填充它。这也适用于(不太可能以这种方式使用的)ScriptExecutionContext 和 CallbackArguments 类型。如果您不知道这些是做什么的,不用担心,它们不是让 MoonSharp 基本工作所必需的!
作为一个好的实践,如果可以的话,总是保留 Script 对象。有些事情(比如创建表)只能使用 Script 对象来完成。

接收一个表

一个表会自动转换为 List<T>。例如:

public static double TableTestReverse()
{string scriptCode = @"    return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }";Script script = new Script();script.Globals["dosum"] = (Func<List<int>, int>)(l => l.Sum());DynValue res = script.DoString(scriptCode);return res.Number;
}

但是,这可能会在某些平台(比如 iOS)上造成问题。有很多方法可以解决这个问题(你会在其他教程中看到),但可以说,以下方法没有任何问题,而且速度更快:

public static double TableTestReverseSafer()
{string scriptCode = @"    return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }";Script script = new Script();script.Globals["dosum"] = (Func<List<object>, int>)(l => l.OfType<int>().Sum());DynValue res = script.DoString(scriptCode);return res.Number;
}

另一种更快的方法是使用 Table 对象:

static double Sum(Table t)
{var nums = from v in t.Valueswhere v.Type == DataType.Numberselect v.Number;return nums.Sum();
}private static double TableTestReverseWithTable()
{string scriptCode = @"    return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }";Script script = new Script();script.Globals["dosum"] = (Func<Table, double>)Sum;DynValue res = script.DoString(scriptCode);return res.Number;
}

但在这里,我们必须处理 DynValue(s)。

要理解所有这些,我们需要更深入地了解 MoonSharp 如何将 Lua 类型映射到 C# 类型,反之亦然。我们将在下一部分中详细讨论。

5.Auto-conversions

这次没有代码。

在深入探讨 MoonSharp 和 CLR 集成之前,我们需要明确类型是如何来回映射的。遗憾的是,反向映射与正向映射有很大不同,因此我们将分别分析这两种情况。

你可能会问,这是不是有点太复杂了?

当然复杂。自动化的东西很好,但当它们失败时,失败的方式却非常复杂。当有疑问或事情变得过于复杂时,你需要简化事情。

有两种方法:要么直接使用 DynValue,要么使用自定义转换器。

这两种解决方案不仅能让你获得理智和简单,而且在速度上也明显快于自动转换!

自定义转换器

可以自定义转换过程,但设置是全局的,会影响所有脚本。

要自定义转换,只需将适当的回调设置为 Script.GlobalOptions.CustomConverters。

例如,如果我们希望在从 CLR 转换为脚本时,将所有 StringBuilder 对象转换为大写字符串,可以这样做:

Script.GlobalOptions.CustomConverters.SetClrToScriptCustomConversion<StringBuilder>(v => DynValue.NewString(v.ToString().ToUpper()));

如果我们想自定义所有表格在与 IList<int> 匹配时的转换方式,我们可以这样写:

Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Table, typeof(IList<int>),v => new List<int>() { ... });

如果一个转换器返回 null,系统会表现得就像没有自定义转换器存在一样,并尝试进行自动转换。

CLR 类型到 MoonSharp 类型的自动转换

这个转换适用于以下情况:

• 从脚本调用的函数返回对象时
• 从用户数据的属性返回对象时  
• 使用索引运算符在表中设置值时
• 调用 DynValue.FromObject 时
• 使用任何以 System.Object 代替 DynValue 作为参数的函数重载时

这个转换实际上非常简单。下表解释了具体的转换规则:

CLR typeC# friendly nameLua typeNotes
void(no value)

This can be applied to return values of methods only.

翻译:这只能应用于方法的返回值。

nullnil

Any null will be converted to nil.

翻译:任何null都将转换为nil。

MoonSharp.Interpreter.DynValue*

The DynValue is passed through.

翻译:DynValue 被传递了。

System.SBytesbytenumber
System.Bytebytenumber
System.Int16shortnumber
System.UInt16ushortnumber
System.Int32intnumber
System.UInt32uintnumber
System.Int64longnumber

The conversion can lead to a silent precision loss.

翻译:转换可能导致精度无声地丢失。

System.UInt64ulongnumber

The conversion can lead to a silent precision loss.

翻译:转换可能导致精度无声地丢失。

System.Singlefloatnumber
System.Decimaldecimalnumber

The conversion can lead to a silent precision loss.

翻译:转换可能导致精度无声地丢失。

System.Doubledoublenumber
System.Booleanboolboolean
System.Stringstringstring
System.Text.StringBuilderstring
System.Charcharstring
MoonSharp.Interpreter.Tabletable
MoonSharp.Interpreter.CallbackFunctionfunction
System.Delegatefunction
System.Objectobjectuserdata

Only if the type has been registered for userdata.

翻译:只有当该类型已经为 userdata 注册过,才可以这样做。

System.Typeuserdata

Only if the type has been registered for userdata, static members access.

翻译:只有当类型已经为 userdata 注册时,才可以访问静态成员。

MoonSharp.Interpreter.Closurefunction
System.Reflection.MethodInfofunction
System.Collections.IListtable

The resulting table will be indexed 1-based. All values are converted using these rules.

翻译:生成的表将使用从1开始的索引。所有的值都会按照以下规则进行转换。

System.Collections.IDictionarytable

All keys and values are converted using these rules.

翻译:所有键和值都会使用这些规则进行转换。

System.Collections.IEnumerableiterator

All values are converted using these rules.

翻译:所有值均依下列规则进行转换。

System.Collections.IEnumeratoriterator

All values are converted using these rules.

翻译:所有值均依下列规则进行转换。

这包括对集合的相当全面的覆盖,因为大多数集合都实现了 IList、IDictionary、IEnumerable 和/或 IEnumerator 接口。如果你正在编写自己的集合,请记得实现这些非泛型接口中的一个。

任何不能使用此逻辑转换的值都将抛出 ScriptRuntimeException。

MoonSharp 类型到 CLR 类型的标准自动转换

相反的转换要复杂得多。实际上,存在两条不同的转换路径--"标准"路径和"受限"路径。当你要求将一个 DynValue 转换为对象而不指定你实际想要接收什么时,应用第一种路径,而当有一个目标 System.Type 要匹配时,则应用另一种路径。

这在以下情况下使用:

  • 调用 DynValue.ToObject 时
  • 使用索引器从表中检索值时
  • 在受限转换的一些特定子情况下(见下文)

这里我们看到默认转换。它实际上很简单:

MoonSharp typeCLR typeNotes
nilnull

Applied to every value which is nil.

翻译:应用于每个值为 nil 的情况。

booleanSystem.Boolean
numberSystem.Double
stringSystem.String
functionMoonSharp.Interpreter.Closure

If DataType is Function.

翻译:如果数据类型是函数(Function)。

functionMoonSharp.Interpreter.CallbackFunction

If DataType is ClrFunction.

翻译:如果数据类型是 CLR 函数(ClrFunction)。

tableMoonSharp.Interpreter.Table
tupleMoonSharp.Interpreter.DynValue[]
userdata(special)

Returns the object stored in userdata. If a "static" userdata, the Type is returned.

翻译:如果是存储在 userdata 中的对象,此方法会返回该对象。如果是“静态”userdata,则返回其类型(Type)。

无法使用此逻辑转换的每个值都将抛出 ScriptRuntimeException 异常。

MoonSharp 类型到 CLR 类型的受限自动转换

非常感谢您提供这些关于 MoonSharp 类型转换的详细信息!我来总结一下要点:

MoonSharp 类型到 CLR 类型的受限自动转换比默认转换要复杂得多。它发生在需要将 MoonSharp 值存储到给定类型的 CLR 变量中的情况下,转换方式几乎有无限多种。

特殊情况:

  • 如果目标类型是 DynValue,则不进行转换,返回原始值。
  • 如果目标类型是 object,则应用默认转换。
  • 如果要映射 nil 值,则 null 映射到引用类型和可空值类型。某些情况下会尝试匹配默认值。否则抛出异常。
  • 如果没有提供值,则尽可能使用默认值。

数据类型转换:

  • 字符串可转换为 String, StringBuilder 或 Char
  • 布尔值可转换为 Boolean 及其可空版本,也可转换为字符串类型
  • 数字可转换为 SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Decimal, Double 及其可空版本,也可转换为字符串类型
  • 函数转换为 Closure, ScriptFunctionDelegate, ClrFunction 或 Func 委托
  • 非静态的 userdata 如果类型兼容则可转换。也可通过 ToString() 转换为字符串类型
  • 表可转换为 Table, Dictionary, List, 数组等多种集合类型,但转换到泛型和类型化数组有一些限制,可能会有性能和兼容性问题

总之,MoonSharp 在类型转换上非常灵活,但复杂类型的转换可能存在一些问题。必要时可以添加自定义转换器来解决。在面向 AOT 平台时,要特别小心值类型的泛型可能引入的不兼容问题。

end

相关文章:

MoonSharp 文档一

目录 1.Getting Started 步骤1&#xff1a;在 IDE 中引入 MoonSharp 步骤2&#xff1a;引入命名空间 步骤3&#xff1a;调用脚本 步骤4&#xff1a;运行代码 2.Keeping a Script around 步骤1&#xff1a;复现前教程所有操作 步骤2&#xff1a;改为创建Script对象 步骤…...

2025-03-08 学习记录--C/C++-PTA 习题10-1 判断满足条件的三位数

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 裁判测试程序样例&#xff1a; #include <stdio.h> #include <math.h>int search( int n );int…...

三星首款三折叠手机被曝外屏6.49英寸:折叠屏领域的新突破

在智能手机的发展历程中,折叠屏手机的出现无疑是一次具有里程碑意义的创新。它打破了传统手机屏幕尺寸的限制,为用户带来了更加多元和便捷的使用体验。而三星,作为手机行业的巨头,一直以来都在折叠屏技术领域积极探索和创新。近日,三星首款三折叠手机的诸多细节被曝光,其…...

大白话Vue Router 中路由守卫(全局守卫、路由独享守卫、组件内守卫)的种类及应用场景

大白话Vue Router 中路由守卫&#xff08;全局守卫、路由独享守卫、组件内守卫&#xff09;的种类及应用场景 答题思路 明确要介绍的内容&#xff1a;需要分别介绍 Vue Router 中全局守卫、路由独享守卫和组件内守卫这三种路由守卫的种类&#xff0c;详细说明它们的定义、使用…...

CUDA编程之OpenCV与CUDA结合使用

OpenCV与CUDA的结合使用可显著提升图像处理性能。 一、版本匹配与环境配置 CUDA与OpenCV版本兼容性‌ OpenCV各版本对CUDA的支持存在差异&#xff0c;例如OpenCV 4.5.4需搭配CUDA 10.0‌2&#xff0c;而较新的OpenCV 4.8.0需使用更高版本CUDA‌。 需注意部分模块&#xff08;…...

Educational Codeforces Round 7 F. The Sum of the k-th Powers 多项式、拉格朗日插值

题目链接 题目大意 求 ( ∑ i 1 n i k ) (\sum_{i1}^{n} i^k) (∑i1n​ik) m o d ( 1 0 9 7 ) mod(10^97) mod(1097) . 数据范围 &#xff1a; 1 ≤ n ≤ 1 0 9 1 \leq n \leq 10^9 1≤n≤109 , 0 ≤ k ≤ 1 0 6 0 \leq k \leq 10^6 0≤k≤106 . 思路 令 f ( n ) ∑ …...

LINUX网络基础 [五] - HTTP协议

目录 HTTP协议 预备知识 认识 URL 认识 urlencode 和 urldecode HTTP协议格式 HTTP请求协议格式 HTTP响应协议格式 HTTP的方法 HTTP的状态码 ​编辑HTTP常见Header HTTP实现代码 HttpServer.hpp HttpServer.cpp Socket.hpp log.hpp Makefile Web根目录 H…...

WPS Word中英文混杂空格和行间距不一致调整方案

文章目录 问题1&#xff1a;在两端对齐的情况下&#xff0c;如何删除参考文献&#xff08;英文&#xff09;的空格问题2&#xff1a;中英文混杂行间距不一致问题问题3&#xff1a;设置中文为固定字体&#xff0c;设置西文为固定字体参考 问题1&#xff1a;在两端对齐的情况下&a…...

C++ Qt创建计时器

在Qt中&#xff0c;可以使用QTimer来创建一个简单的计时器。QTimer是一个用于定时触发事件的类&#xff0c;通常与QObject的子类&#xff08;如QWidget&#xff09;一起使用。以下是一个完整的示例&#xff0c;展示如何使用Qt创建一个带有计时器的窗口应用程序。 示例&#xff…...

CSDN博客:Markdown编辑语法教程总结教程(中)

❤个人主页&#xff1a;折枝寄北的博客 Markdown编辑语法教程总结 前言1. 列表1.1 无序列表1.2 有序列表1.3 待办事项列表1.4 自定义列表 2. 图片2.1 直接插入图片2.2 插入带尺寸的图片2.3 插入宽度确定&#xff0c;高度等比例的图片2.4 插入高度确定宽度等比例的图片2.5 插入居…...

nlp培训重点-5

1. LoRA微调 loader&#xff1a; # -*- coding: utf-8 -*-import json import re import os import torch import numpy as np from torch.utils.data import Dataset, DataLoader from transformers import BertTokenizer """ 数据加载 """cl…...

电子学会—2024年月6青少年软件编程(图形化)四级等级考试真题——水仙花数

水仙花数 如果一个三位数等于它各个数位上的数字的立方和&#xff0c;那么这个数就是水仙花数&#xff0c;例如:153 111 555 333&#xff0c;153就是一个水仙花数。 1.准备工作 (1)保留默认角色小猫; (2)白色背景。 2.功能实现 (1)使用循环遍历所有三位数&#xff0c;把所…...

若依分页的逻辑分析

看了一些网上的感觉都是 听君一席话, 如听一席话. 下面开始简单的分析一下, 随便找一个接口, 看一下前端的请求地址: 请求方式: GET 请求地址: http://localhost/dev-api/system/role/list?pageNum1&pageSize10 后端接口: PreAuthorize("ss.hasPermi(system:role:li…...

JetBrains学生申请

目录 JetBrains学生免费授权申请 IDEA安装与使用 第一个JAVA代码 1.利用txt文件和cmd命令运行 2.使用IDEA新建项目 JetBrains学生免费授权申请 本教程采用学生校园邮箱申请&#xff0c;所以要先去自己的学校申请校园邮箱。 进入JetBrains官网 点击立即申请&#xff0c;然…...

【算法方法总结·五】链表操作的一些技巧和注意事项

【算法方法总结五】链表操作的一些技巧和注意事项 【算法方法总结一】二分法的一些技巧和注意事项【算法方法总结二】双指针的一些技巧和注意事项【算法方法总结三】滑动窗口的一些技巧和注意事项【算法方法总结四】字符串操作的一些技巧和注意事项【算法方法总结五】链表操作…...

langchain系列(终)- LangGraph 多智能体详解

目录 一、导读 二、概念原理 1、智能体 2、多智能体 3、智能体弊端 4、多智能体优点 5、多智能体架构 6、交接&#xff08;Handoffs&#xff09; 7、架构说明 &#xff08;1&#xff09;网络 &#xff08;2&#xff09;监督者 &#xff08;3&#xff09;监督者&…...

侯捷 C++ 课程学习笔记:深入理解智能指针

文章目录 每日一句正能量一、引言二、智能指针的核心概念&#xff08;一&#xff09;std::unique_ptr&#xff08;二&#xff09;std::shared_ptr&#xff08;三&#xff09;std::weak_ptr 三、学习心得四、实际应用案例五、总结 每日一句正能量 如果说幸福是一个悖论&#xff…...

访问不了 https://raw.githubusercontent.com 怎么办?

修改 Hosts 文件&#xff08;推荐&#xff09;​ 原理&#xff1a;通过手动指定域名对应的 IP 地址&#xff0c;绕过 DNS 污染。 步骤&#xff1a; 1、访问 IPAddress.com&#xff0c;搜索 raw.githubusercontent.com&#xff0c;获取当前最新的 IPv4 地址&#xff08;例如 1…...

大模型工程师学习日记(十五):Hugging Face 模型微调训练(基于 BERT 的中文评价情感分析)

1. datasets 库核心方法 1.1. 列出数据集 使用 d atasets 库&#xff0c;你可以轻松列出所有 Hugging Face 平台上的数据集&#xff1a; from datasets import list_datasets# 列出所有数据集 all_datasets list_datasets()print(all_datasets)1.2. 加载数据集 你可以通过 l…...

Codeforces Round 258 (Div. 2) E. Devu and Flowers 生成函数

题目链接 题目大意 有 n n n ( 1 ≤ n ≤ 20 ) (1\leq n \leq 20) (1≤n≤20) 个花瓶&#xff0c;第 i i i 个花瓶里有 f i f_i fi​ ( 1 ≤ f i ≤ 1 0 12 ) (1\leq f_i \leq 10^{12}) (1≤fi​≤1012) 朵花。现在要选择 s s s ( 1 ≤ s ≤ 1 0 14 ) (1\leq s \leq 1…...

MySQL-----SELECT语句-查询

目录 SELECT语句-查询 1.格式 2.操作 3.算数表达式 SELECT语句-查询 1.格式 &#x1f4d6;简单查询: 格式: select 字段1,字段n from 表名&#xff1b; 起别名: 通过在字段后添加 as 别名 as可以省略 改变表头 eg: select username "用户名",password as "…...

子数组、子串系列(典型算法思想)—— OJ例题算法解析思路

一、53. 最大子数组和 - 力扣&#xff08;LeetCode&#xff09; 算法代码&#xff1a; class Solution { public:int maxSubArray(vector<int>& nums) {// 1. 创建 dp 表// dp[i] 表示以第 i 个元素结尾的子数组的最大和int n nums.size();vector<int> dp(n…...

Windows编程----进程的当前目录

进程的当前目录 Windows Api中有大量的函数在调用的时候&#xff0c;需要传递路径。比如创建文件&#xff0c;创建目录&#xff0c;删除目录&#xff0c;删除文件等等。拿创建文件的CreateFile函数做比喻&#xff0c;如果我们要创建的文件路径不是全路径&#xff0c;那么wind…...

AVL树的介绍及实现

文章目录 &#xff08;一&#xff09;AVL的概念&#xff08;二&#xff09;AVL树的实现1.AVL树的结构2.AVL树的插入3.AVL树的查找 &#xff08;三&#xff09;检查一棵树是否是AVL树 &#xff08;一&#xff09;AVL的概念 AVL树是一棵高度平衡的二叉搜索树&#xff0c;通过控制…...

hadoop第3课(hdfs shell常用命令)

一、Hadoop FS 基础操作命令 1. 查看帮助 hadoop fs -help [命令名] # 查看具体命令的帮助文档 # 示例&#xff1a; hadoop fs -help mkdir2. 目录操作 hadoop fs -mkdir /path # 创建目录 hadoop fs -mkdir -p /path/a/b # 递归创建多级目录 hadoop fs -rmdir …...

为什么Java不采用引用传递方式

Java不采用引用传递方式,而是统一采用值传递机制,这一设计决策背后有多种原因。 1. 语言设计的简洁性与一致性 Java的设计目标之一是保持语言的简洁性和一致性。如果同时支持值传递和引用传递,可能会导致语言复杂度增加,使得开发者难以理解和使用。通过统一采用值传递机制…...

【RAG】文本分割的粒度

文本分隔 可能存在的问题 粒度太大可能导致检索不精准粒度太小可能导致信息不全面问题的答案可能跨越两个片段 # 创建一个向量数据库对象 vector_db MyVectorDBConnector("demo_text_split", get_embeddings) # 向向量数据库中添加文档 vector_db.add_documents(p…...

Qt信号与槽机制实现原理

Qt 的信号和槽机制是其核心特性之一&#xff0c;用于实现对象间的松耦合通信。以下是对其实现原理的详细分析&#xff1a; 1. 元对象系统&#xff08;Meta-Object System&#xff09; Q_OBJECT 宏与 moc Qt 通过元对象系统实现反射能力。声明 Q_OBJECT 宏的类会由 moc&#xf…...

Vue3 中 Computed 用法

Computed 又被称作计算属性&#xff0c;用于动态的根据某个值或某些值的变化&#xff0c;来产生对应的变化&#xff0c;computed 具有缓存性&#xff0c;当无关值变化时&#xff0c;不会引起 computed 声明值的变化。 产生一个新的变量并挂载到 vue 实例上去。 vue3 中 的 com…...

《今日AI-人工智能-编程日报》

一、AI行业动态 AI模型作弊行为引发担忧 最新研究表明&#xff0c;AI在国际象棋对弈中表现出作弊倾向&#xff0c;尤其是高级推理模型如OpenAI的o1-preview和DeepSeek的R1模型。这些模型通过篡改代码、窃取棋路等手段试图扭转战局&#xff0c;且作弊行为与其智能水平正相关。研…...