宣布Span<T>
时,我想在解析器中使用它作为我的玩具编程语言。 (实际上,我可能会存储一个Memory<char>
,但这不是重点。)
但是,我已经习惯于开启字符串:
switch (myString) {
case "function":
return TokenType.Function;
// etc.
}
开启一个Span<char>
不会工作,并分配一个字符串进行比较以防止使用Span的目的。
切换到使用if-else语句会导致同样的问题。
那么,有没有办法有效地做到这一点? ToString()
上的Span<char>
是否未分配?
答案 0 :(得分:3)
System.MemoryExtensions
包含用于比较Span
s内容的方法。
使用支持String
和ReadOnlySpan<char>
之间的隐式转换的.NET Core,您将拥有:
ReadOnlySpan<char> myString = "function";
if (MemoryExtensions.Equals(myString, "function", StringComparison.Ordinal))
{
return TokenType.Function;
}
else if (MemoryExtensions.Equals(myString, "...", StringComparison.Ordinal))
{
...
}
我在这里显式调用MemoryExtensions.Equals
是因为这样可以满足将字符串文字(例如"function"
)隐式转换为ReadOnlySpan<char>
以进行比较的要求。如果要以面向对象的方式调用此扩展方法,则需要显式使用AsSpan
:
if (myString.Equals("function".AsSpan(), StringComparison.Ordinal))
如果您特别喜欢switch
语句,则可以滥用模式匹配功能来偷偷进行比较,但这看起来不太可读甚至没有帮助:
ReadOnlySpan<char> myString = "function";
switch (myString)
{
case ReadOnlySpan<char> s when MemoryExtensions.Equals(s, "function", StringComparison.Ordinal):
return TokenType.Function;
break;
case ReadOnlySpan<char> s when MemoryExtensions.Equals(s, "...", StringComparison.Ordinal):
...
break;
}
如果您不使用.Net Core,而不得不分别install进行System.Memory NuGet程序包,则需要在每个字符串文字后附加.AsSpan()
。
答案 1 :(得分:1)
调用ToString()
会导致分配,因为字符串是不可变的,但是您可以考虑使用各种MemoryExtensions Class方法执行比较。因此,您可以将源代码保留在Span<char>
中,并使用如下代码:
System.ReadOnlySpan<char> myString = "function test();".AsSpan();
if (myString.StartsWith("function".AsSpan()))
Console.WriteLine("function");
这将导致为每个令牌分配中间的字符串(myString分配只是为了演示),但是您可以将令牌表初始化为令牌解析器方法外部的一次性操作。另外,您可能想研究一下Slice
方法,这是在解析代码时浏览代码的有效方法。
感谢GSerg指出.NET Core可以处理从string
到ReadOnlySpan<char>
的隐式转换,因此,如果使用AsSpan()
,则可以省略function keyPressed() {
if (keyIsDown(ENTER)){
player.up();
}
}
this.up = function() {
if (this.y == 350){
if (keyIsDown(ENTER)){
this.velocity -= this.gravity*15;
}
else{
this.velocity += this.gravity*20000;
}
}
}
.NET Core。