Syntax
字符串文字百分比
这是一台正在接收%
报文的字符串文字百分比.
A 字符串文字百分比的形式为:
%
个字符
- opening-delimiter个
- 字符串内容
- closing-delimiter个
如果opening-delimiter个是<
、[
、(
或{
之一,则closing-delimiter个必须是对应的>
、]
、)
或}
.否则,opening-delimiter个可以是任意字符,而closing-delimiter个必须是相同的字符.
我们开始吧.
%
(即,%
空间空间)
是一个字符串文字百分比,以空格为分隔符,没有内容.即等于""
.
Operator Message Send a % b
a % b
相当于
a.%(b)
即sending the message %
赋给表达式a
的求值结果,将表达式b
求值的结果作为单个自变量传递.
这意味着
% % b
(大致)相当于
"".%(b)
参数列表
我们开始吧. what's b
then? Well, it's the expression following the %
operator (not to be confused with the %
sigil of the 字符串文字百分比).
The entire code (大致)相当于 this:
def count(str)
state = :start
tbr = []
str.each_char do
"".%(case state
when :start
tbr << 0
"".%(state = :symbol)
""when :symbol
tbr << 1
"".%(state = :start)
""end)
end
tbr
end
p count("Foobar")
天冬氨酸
您只需问Ruby就可以自己解决这个问题:
# ruby --dump=parsetree_with_comment test.rb
###########################################################
## Do NOT use this node dump for any purpose other than ##
## debug and research. Compatibility is not guaranteed. ##
###########################################################
# @ NODE_SCOPE (id: 62, line: 1, location: (1,0)-(17,17))
# | # new scope
# | # format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body
# +- nd_tbl (local table): (empty)
# +- nd_args (arguments):
# | (null node)
[…]
# | | +- nd_body (body):
# | | @ NODE_OPCALL (id: 48, line: 5, location: (5,0)-(12,7))*
# | | | # method invocation
# | | | # format: [nd_recv] [nd_mid] [nd_args]
# | | | # example: foo + bar
# | | +- nd_mid (method id): :%
# | | +- nd_recv (receiver):
# | | | @ NODE_STR (id: 12, line: 5, location: (5,0)-(5,3))
# | | | | # string literal
# | | | | # format: [nd_lit]
# | | | | # example: 'foo'
# | | | +- nd_lit (literal): ""
# | | +- nd_args (arguments):
# | | @ NODE_LIST (id: 47, line: 5, location: (5,4)-(12,7))
# | | | # list constructor
# | | | # format: [ [nd_head], [nd_next].. ] (length: [nd_alen])
# | | | # example: [1, 2, 3]
# | | +- nd_alen (length): 1
# | | +- nd_head (element):
# | | | @ NODE_CASE (id: 46, line: 5, location: (5,4)-(12,7))
# | | | | # case statement
# | | | | # format: case [nd_head]; [nd_body]; end
# | | | | # example: case x; when 1; foo; when 2; bar; else baz; end
# | | | +- nd_head (case expr):
# | | | | @ NODE_DVAR (id: 13, line: 5, location: (5,9)-(5,14))
# | | | | | # dynamic variable reference
# | | | | | # format: [nd_vid](dvar)
# | | | | | # example: 1.times { x = 1; x }
# | | | | +- nd_vid (local variable): :state
[…]
这里一些有趣的地方是(id: 12, line: 5, location: (5,0)-(5,3))
处的 node ,它是第一个字符串文字,以及(id: 48, line: 5, location: (5,0)-(12,7))
,它是发送的第一个%
消息:
# | | +- nd_body (body):
# | | @ NODE_OPCALL (id: 48, line: 5, location: (5,0)-(12,7))*
# | | | # method invocation
# | | | # format: [nd_recv] [nd_mid] [nd_args]
# | | | # example: foo + bar
# | | +- nd_mid (method id): :%
# | | +- nd_recv (receiver):
# | | | @ NODE_STR (id: 12, line: 5, location: (5,0)-(5,3))
# | | | | # string literal
# | | | | # format: [nd_lit]
# | | | | # example: 'foo'
# | | | +- nd_lit (literal): ""
注意:这只是获取解析树的最简单的方法,不幸的是,它包含了许多内部细节,与弄清楚发生了什么并不真正相关.还有其他方法,如parser
gem或其配套的ast
,可以产生更具可读性的结果:
# ruby-parse count.rb
(begin
(def :count
(args
(arg :str))
(begin
(lvasgn :state
(sym :start))
(lvasgn :tbr
(array))
(block
(send
(lvar :str) :each_char)
(args)
(send
(dstr) :%
(case
(lvar :state)
(when
(sym :start)
(begin
(send
(lvar :tbr) :<<
(int 0))
(send
(dstr) :%
(lvasgn :state
(sym :symbol)))
(dstr)))
(when
(sym :symbol)
(begin
(send
(lvar :tbr) :<<
(int 1))
(send
(dstr) :%
(lvasgn :state
(sym :start)))
(dstr))) nil)))
(lvar :tbr)))
(send nil :p
(send nil :count
(str "Foobar"))))
Semantics
到目前为止,我们所讨论的都是Syntax,即代码的语法 struct .但它是做什么的mean?
方法String#%
执行String Formatting和printf
family of functions.然而,由于格式字符串(%
消息的接收者)是空字符串,因此消息发送的结果也是空字符串,因为没有要格式化的内容.
如果Ruby是一种纯粹的函数式、懒惰、非严格的语言,结果将等同于:
def count(str)
state = :start
tbr = []
str.each_char do
"".%(case state
when :start
tbr << 0
""
""when :symbol
tbr << 1
""
""end)
end
tbr
end
p count("Foobar")
which in turn 相当于 this
def count(str)
state = :start
tbr = []
str.each_char do
"".%(case state
when :start
tbr << 0
""
when :symbol
tbr << 1
""
end)
end
tbr
end
p count("Foobar")
which 相当于 this
def count(str)
state = :start
tbr = []
str.each_char do
"".%(case state
when :start
""
when :symbol
""
end)
end
tbr
end
p count("Foobar")
which 相当于 this
def count(str)
state = :start
tbr = []
str.each_char do
"".%(case state
when :start, :symbol
""
end)
end
tbr
end
p count("Foobar")
which 相当于 this
def count(str)
state = :start
tbr = []
str.each_char do
""
end
tbr
end
p count("Foobar")
which 相当于 this
def count(str)
state = :start
tbr = []
tbr
end
p count("Foobar")
which 相当于 this
def count(str)
[]
end
p count("Foobar")
显然,这不是正在发生的事情,原因是Ruby isn't是一种纯粹的函数式、懒惰、非严格的语言.虽然传递给%
个消息发送的参数是irrelevant to the result of the message send个,但它们仍然会被计算(因为Ruby是严格的和Eager 的),并且它们有副作用(因为Ruby不是纯粹的函数式的),即它们的重新赋值变量和改变tbr
结果数组的副作用仍然会被执行.
如果这段代码是以一种更像Ruby的风格编写的,Mutations 更少,副作用更少,而是使用函数转换,那么任意用空字符串替换结果会立即 destruct 它.这里没有效果的唯一原因是副作用和Mutations 的大量使用.