在改变对象时使用ruby字符串插值

时间:2018-04-13 11:57:34

标签: ruby

使用字符串插值在传递给函数后打印对象及其值时遇到了一些奇怪的行为。

print "#{obj} => #{function obj}"

它为#{obj}#{function obj}

输出了类似的内容

我得出的结论是,因为我的function是一个变异函数。 我可以轻松地重现输出:

def mutate_the_object(obj)
  obj.concat '1'
end
obj = '1'
print "#{obj} != #{mutate_the_object obj} != #{mutate_the_object obj} != #{obj}"

=> 111!= 111!= 111!= 111

为什么字符串插值给出4个相等的字段?我认为结果会是这样的:

=> 1!= 11!= 111!= 111

2 个答案:

答案 0 :(得分:1)

我查看了ISO Ruby语言规范,RubySpec和内插String文字的RDoc,三者都没有定义插值的特定评估顺序。他们可能 明确地说评估顺序是未定义的,但是未明确定义的事实意味着它是隐式未定义的。

因此,换句话说:如果你的插值有副作用,这些副作用相对于彼此的顺序和它们插入字符串的时间是未指定的,你所观察到的是一个完全合法的规范实施。

据我所知,(至少)以下任何结果都是合法的:

'1 != 11 != 111 != 1'
'1 != 11 != 111 != 11'
'1 != 11 != 111 != 111'
'1 != 111 != 11 != 1'
'1 != 111 != 11 != 11'
'1 != 111 != 11 != 111'
'1 != 111 != 111 != 1'
'1 != 111 != 111 != 11'
'1 != 111 != 111 != 111'
'11 != 11 != 111 != 1'
'11 != 11 != 111 != 11'
'11 != 11 != 111 != 111'
'11 != 111 != 11 != 1'
'11 != 111 != 11 != 11'
'11 != 111 != 11 != 111'
'11 != 111 != 111 != 1'
'11 != 111 != 111 != 11'
'11 != 111 != 111 != 111'
'111 != 11 != 111 != 1'
'111 != 11 != 111 != 11'
'111 != 11 != 111 != 111'
'111 != 111 != 11 != 1'
'111 != 111 != 11 != 11'
'111 != 111 != 11 != 111'
'111 != 111 != 111 != 1'
'111 != 111 != 111 != 11'
'111 != 111 != 111 != 111'

答案 1 :(得分:1)

String#concat更改对象并将其返回。

def mutate_the_object将它接收的对象更改为参数并返回它。

似乎首先计算插值表达式,然后使用它们的值来计算字符串,以类似的方式使用C函数sprintf()

问题中张贴的代码相当于:

def mutate_the_object(obj)
  obj.concat '1'
end
obj = '1'
obj1 = mutate_the_object obj
obj2 = mutate_the_object obj
print "#{obj} != #{obj1} != #{obj2} != #{obj}"

obj1obj2是包含与obj相同对象的引用的变量。

这可以通过运行来轻松证明:

print <<END
    #{obj.__id__}
    #{(mutate_the_object obj).__id__}
    #{(mutate_the_object obj).__id__}
    #{obj.__id__}
END