Groovy支持/
作为除法运算符:
groovy> 1 / 2
===> 0.5
它支持/
作为字符串分隔符,甚至可以是多行:
groovy> x = /foo/
===> foo
groovy:000> x = /foo
groovy:001> bar/
===> foo
bar
鉴于此,为什么我不能在groovysh中评估一个斜线字符串文字?
groovy:000> /foo/
groovy:001>
很明显,groovysh认为这种情况由于某种原因而未被终止。
groovy如何避免在分裂和字符串之间混淆?这段代码意味着什么:
groovy> f / 2
这是一个函数调用f(/2 .../)
,其中/
开始多行斜线字符串,或f
除以2?
答案 0 :(得分:2)
我不完全确定Groovy是如何做到的,但我会描述我是如何做到的,如果Groovy没有以类似的方式工作,我会非常惊讶。
我听说过的大多数解析算法(Shunting-yard,Pratt等)都能识别两种不同的令牌:
为了方便起见,从这一点开始,我将把前一种令牌称为运算符,将后者称为非运算符。
现在,关于这种区别的有趣之处在于它不是基于令牌实际上是什么,而是基于直接上下文,特别是前面的令牌。因此,根据代码中的位置以及解析器是将其分类为运算符还是非运算符,可以对相同的标记进行非常不同的解释。例如,如果在操作员位置,则“-
”标记表示减法,但非操作员位置中的相同标记是否定。决定“-
”是否为减法运算符没有问题,因为您可以根据其上下文来判断。
一般来说,对于Groovy中的“/
”字符也是如此。如果前面有表达式,则将其解释为运算符,这意味着它是一个除法。否则,它是一个非运算符,使其成为字符串文字。所以,你通常可以通过查看紧接在它之前的令牌来判断'/
'是否是一个除法:
/
”是分区,如果它跟在标识符,文字,后缀运算符,右括号或表示表达式结尾的其他标记之后。/
'跟在前缀运算符,中缀运算符,左括号或其他此类标记之后,或者如果它开始一行,则“println / foo
”开始字符串。当然,在实践中并不是那么简单。 Groovy设计为在面对各种样式和用途时具有灵活性,因此分号或括号等内容通常是可选的。这有时会使解析有些模棱两可。例如,假设我们的解析器遇到以下行:
foo
这很可能是打印多行字符串的尝试:println
是作为参数传递给groovysh
的字符串的开头,并且省略了参数列表周围的可选括号。当然,对于一个简单的解析器,它看起来像一个分区。我希望Groovy解析器可以通过向前读取以下行来看出差异,看看哪个解释没有给出错误,但是像groovysh
这样的东西实际上是不可能的(因为,作为repl,它不会但是可以访问更多行),所以它被迫只是猜测。
和以前一样,我不知道确切的原因,但我确实知道因为groovysh
是一个repl,它对于更模糊的规则会遇到更多麻烦。即便如此,一个简单的单行斜线字符串也是非常明确的,所以我相信其他东西可能会在这里发生。以下是我在> /foo - unexpected char: '/' @ line 2, column 1.
> /foo/ - awaits further input
> /foo/bar - unexpected char: '/' @ line 2, column 1.
> /foo/bar/ - awaits further input
> /foo/ + 'bar' - unexpected char: '/' @ line 2, column 1.
> 'foo' + /bar/ - evaluates to 'foobar'
> /foo/ - evaluates to 'foo'
> /foo - awaits further input
> /foo/bar - Unknown property: bar
中使用各种表单的结果:
/
当'unexpected char: '/' @ line 2, column 1.
'字符是一行中的第一个字符时,似乎会发生奇怪的事情。它似乎遵循的模式(据我所知)是:
/
。我也注意到了一些有趣的观点:
\
)和反斜杠(groovyConsole
)似乎都很重要,似乎完全可以互换。groovysh
或实际的Groovy文件中根本没有发生。groovysh
正确解释它,但前提是斜杠是正斜杠而不是反斜杠。所以,我个人认为这只是{{1}}的一个怪癖,要么是一个我没有听说过的错误或一些记录不足的功能。