论坛首页 编程语言技术论坛

Ruby'陷阱'之: '||=' 的真正展开式

浏览 9083 次
精华帖 (0) :: 良好帖 (9) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-06-28  
lllyq 写道
讨论研究是相互的,你是不是太自信了,事实上你的每一行代码我从一开始都试过了才回贴的,希望看到这里的朋友也试试看,LZ不愿意尝试也没问题,你们自己试试看是怎样,否则可能会被这个标题误导

另外关于define的问题还有另一个解释,一般我们都在方法体用,就不存在define的问题,因为如果未定义会自动使用local变量


老实说不是我不愿意尝试,而是我不知道如何根据你的说法来尝试.

其实对于这个问题我自己也是一肚子疑惑, 所以才会发文, 看看大家是否还有更好的解释? Quake Wang就纠正了我的结论.

但从你的回复中,我实在不知道如何去根据你的"说法"转换成展开式, 恕我愚钝, 请指点, 希望继续讨论

0 请登录后投票
   发表时间:2008-06-28  
你可以试试看新开irb,执行
if a then a else a = 2 end
这个效果跟新开irb,执行
a || a = 2 效果是一样的,ruby 版本是1.8.6

非要用一个准确的展开式下面这个应该可以
if defined?(a) then (a || a = b) else a = nil end
0 请登录后投票
   发表时间:2008-06-28  
lllyq 写道
你可以试试看新开irb,执行
if a then a else a = 2 end
这个效果跟新开irb,执行
a || a = 2 效果是一样的,ruby 版本是1.8.6

非要用一个准确的展开式下面这个应该可以
if defined?(a) then (a || a = b) else a = nil end

rubynroll的意思是
你新开irb 执行a ||= 2和
新开irb执行a || a = 2的结果是不一样的,所以这2个公式不是等价的

这样说来我前面的公式也不行...
0 请登录后投票
   发表时间:2008-06-28  
Quake Wang 写道
lllyq 写道
你可以试试看新开irb,执行
if a then a else a = 2 end
这个效果跟新开irb,执行
a || a = 2 效果是一样的,ruby 版本是1.8.6

非要用一个准确的展开式下面这个应该可以
if defined?(a) then (a || a = b) else a = nil end

rubynroll的意思是
你新开irb 执行a ||= 2和
新开irb执行a || a = 2的结果是不一样的,所以这2个公式不是等价的

这样说来我前面的公式也不行...


这个我没有否定,我一开始只是说不用搞这么复杂去涉及define的问题,而且他的结论展开式为 if a then a else a = 2 end 是不对的,看我第一个回帖的分析,以及上一个回帖的说明
0 请登录后投票
   发表时间:2008-06-29  
好,也用代码说事:
先执行一边楼主的代码
h = Hash.new(1)  # 生成一个新的Hash,缺省值为1  
=> {}  
h[:x]  
=> 1    # h[:x]未定义,所以返回1  
h[:x] ||= 2  
=> 1  
h  
=> {}     
h[:x] || h[:x] = 2  
=> 1  
h  
=> {}  #恩,还是{}

可见针对楼主hash的代码,david观点没错。
楼主应该知道,hash的[]是个方法,用个简单的类模拟一下
class A
  def []
    defined?(@a) ? @a : 1
  end

  def []=(a)
    @a = a
  end
end


试一下:
a = A.new
a[]                  # => 1 undefined.
a[] ||= 2          # => 1 undefined.
a[] || a[] = 2    # => 1 还是一样的

#当然如果没有[]方法中 defined? 的保护,直接执行
a || a = 2
#肯定是要有错误的,因为a未定义


当然,我前面说的相当于
a = nil #定义
a || a = b

是不能满足上边A的例子的(同样对楼主hash的例子有问题),但是如果根据上边的理解,david说的 a ||= b 相当于 a || a = b没什么问题。
所以我说支持 lllyq 的观点,可能是 ||= 因为随后就是赋值操作,没有raise undefined错误?这可能真得看了源码才知道了。
0 请登录后投票
   发表时间:2008-06-29  
rubynroll 写道
lllyq 写道
这个h[:x]行为有什么特别么?跟预期的行为一致啊
h[:x] ||= 2 并没有对h[:x]赋值,相当于h[:x] || h[:x] = 2,而h[:x] = nil是有一个赋值动作


我举的那个例子就是为了反驳
caryl 写道

同意楼上,感觉应该相当于
a = nil
a || a = b


caryl说的"楼上"就是
lllyq 写道
a || a = b 就是 a || a = b,本来就没考虑defined?的问题,跟 if a then a else a = b end 一样的,如果你执行下来不一样那估计是你连续执行的问题,前一句相当于做了define



另外, h[:x] ||= 2 相当于h[:x] || h[:x] = 2在这里之所以成立,是因为h这个Hash是已经定义过了. 对于一个通用的 a ||= b, 并不能简单地展开成 a || a = b, 因为这里的a如果未定义就会是个例外.

注意, 这里探讨的是"完全等同"的展开式, 因为如果存在特例, 除非语言规范明白地告诉你"这是个特例", 否则'陷阱'就有可能在那里等着你.

0 请登录后投票
   发表时间:2008-06-30  
lllyq 写道
你可以试试看新开irb,执行
if a then a else a = 2 end
这个效果跟新开irb,执行
a || a = 2 效果是一样的,ruby 版本是1.8.6

效果不一样, 至少在版本是1.8.6. 1.8.7上是不一样的, 后者会raise undefined error.

lllyq 写道

非要用一个准确的展开式下面这个应该可以
if defined?(a) then (a || a = b) else a = nil end

这就是我所想要的讨论的,一个准确的展开式.

但是这个式子还是有问题, 应该是这样才对:
if defined?(a) then (a || a = b) else a = b end

所以结论是不是这样:
1) a ||= b 不等效于: a = a || b
2) 在a已经定义过时, a ||= b等效于a || a = b
3) 在a未定义时, a ||= b等效于a = b
所以归纳起来,准确的展开式应该是:
if defined?(a) then (a || a = b) else a = b end


意见??





0 请登录后投票
   发表时间:2008-06-30  
rubynroll 写道
lllyq 写道
你可以试试看新开irb,执行
if a then a else a = 2 end
这个效果跟新开irb,执行
a || a = 2 效果是一样的,ruby 版本是1.8.6

效果不一样, 至少在版本是1.8.6. 1.8.7上是不一样的, 后者会raise undefined error.

根据你的回复我估计你还是没去试,显然,无论在1.8.6, 1.8.7,后者都会raise undefined error. 前者你试过了么?试过后你就知道为什么我会回第一个帖了\

我说的更清楚一点就是你测试下来两者行为不一样,那是因为你的测试方法不对,你没有每次都新开irb来测试,所以测试方法不对你看到的结果就不对,得出的结论也就不对了
0 请登录后投票
   发表时间:2008-06-30  
lllyq 写道
rubynroll 写道
lllyq 写道
你可以试试看新开irb,执行
if a then a else a = 2 end
这个效果跟新开irb,执行
a || a = 2 效果是一样的,ruby 版本是1.8.6

效果不一样, 至少在版本是1.8.6. 1.8.7上是不一样的, 后者会raise undefined error.

根据你的回复我估计你还是没去试,显然,无论在1.8.6, 1.8.7,后者都会raise undefined error. 前者你试过了么?试过后你就知道为什么我会回第一个帖了\

我说的更清楚一点就是你测试下来两者行为不一样,那是因为你的测试方法不对,你没有每次都新开irb来测试,所以测试方法不对你看到的结果就不对,得出的结论也就不对了


哈哈我真是搞糊涂了,我试的是a ||= 2和a || a = 2, 比较的太多了,连自己都弄糊涂了, 看来此贴应该归新手贴才对:(


至于结论, 你认为 a ||= b最终展开为 if defined?(a) then (a || a = b) else a = b end 还有问题么?
0 请登录后投票
   发表时间:2008-06-30  
:) 没问题,或者
a = defined?(a) ? (a || a = b) : b
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics