一个很容易中招的地方
def self.rule_exchange_anhao(tao_deal)
find_rule_by_operation_name(operation_name) if operation_name = tao_deal_operation_name(tao_deal)
end
以上写法是错误的,同行 if 语句的内容部分引用到的变量的话,一定要在用之前就声明,不然会报错的
undefined local variable or method `operation_name' for #<Class:0x8c83d38>
应该改为多行 if 语句
def self.rule_exchange_anhao(tao_deal)
if operation_name = tao_deal_operation_name(tao_deal)
find_rule_by_operation_name(operation_name)
end
end
刚才中招了
@HungYuHei 哪加括号?
a = b if (b = 1.to_s)
这样?
undefined local variable or method `b' for #<Object:0x7fb6b7b242b8>
#2 楼 @HungYuHei 说的对,加个括号就 ok
find_rule_by_operation_name(operation_name) if (operation_name = tao_deal_operation_name(tao_deal))
是不是优先级问题?
cc=ee 是赋值语句,返回永远是 true,除非 ee 的值是 nil 或 false 所以 if(cc=ee) 是错误的,ruby1.9 会有 warning: found = in conditional, should be ==
因该写成 if cc==ee .用两个等于号. 这是语言基础,也就那最基本的 10 页教程。
@zhaoguobin no! 加括号没有用的 @sevk cc=ee 是赋值语句,返回永远是 true 我觉得这句很有问题 ruby 里面返回的是赋值后的值 这里值为 nil 的话是不会执行下去的...
( operation_name = tao_deal_operation_name(tao_deal) ) && find_rule_by_operation_name(operation_name)
如果想少两句代码,这种方式是比较推荐的。符合一般理解
前几天看到 Rubinius 的开发者抱怨 MRI2.0 会在后置条件里赋值的时候强制输出 warning: https://twitter.com/brixen/status/233688352552005632
至于还有这么奇怪的差异可能他还没发现,,,大概是 MRI 里对后置的 if/unless 处理有所不同。而 Rubinius 返回的结果是正常的(没有让我惊讶)。
Ruby 這點的確不爽,不過全局的$n可以這麼用還是很給力的。
foo[$1] = $2 if 'name = value' =~ /(.*)\s*=\s*(.*)/
if operation_name = tao_deal_operation_name(tao_deal)
#do some thing
end
# 重构如下
operation_name = tao_deal_operation_name(tao_deal)
if operation_name
#do some thing
end
if 语句中 不应该出现 一个等号。 因为, 一个等号 和 两个等号 看起了 极度相似, 不仔细看,会造成混乱。 这是一个坏习惯。
使用=(赋值符号)的返回作为表达式的值是可以的,但是记得在记得在两边加上括号。
# 好的 - 表明了赋值的意图
if (v = array.grep(/foo/)) ...
# 不好的
if v = array.grep(/foo/) ...
# 好的 - 不仅表明了赋值,还表明了正确的优先级
if (v = self.next_value) == "hello" ...
不是不能用,只是不推荐而已。我看着还是别扭,这就好像重构里面讲,你通过方法参数传递进来一个参数,然后在方法体内,又对这个参数重新赋值一样,这样方法里的参数还是原来的那个参数吗?你可以这样用,不过你到底是要传递形参进来,还是赋值?而且对于 Ruby 这种传值而不是传引用的动态语言,会引起歧义。
有时候多一行代码更清晰一些。看似小问题,你可能在几个月后,浏览代码,在这个地方栽跟头。
该什么语义就什么语义,这绝对不会阻碍你写出优质的代码。Wiki 上只是说如果非要那么写,一定加括号,这是好的风格 (虽然不加括号一样执行正确), 但是并不代表支持那么写。
#28 楼 @zw963 In-logic assignment 是 Ruby Idiom。大家都这么用,甚至流行的 code stye 也推荐。
多一行代码更清晰一些
。。。真不能理解。。。
刚才随便在 Rails 和 Rubinius 里找了几行,讨论问题还是要回到现实世界:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/sanitization.rb#L59 https://github.com/rails/rails/blob/master/activerecord/lib/active_record/reflection.rb#L298 https://github.com/rails/rails/blob/master/activerecord/lib/active_record/nested_attributes.rb#L281 https://github.com/rubinius/rubinius/blob/master/lib/un.rb#L227
一流的代码是简单明了,
实在理解不了你的简单明了
....
而不是玩弄语法。
这不叫玩语法,这叫入乡随俗。就像函数式语言里用列表解析是习俗,而嵌套循环就是奇葩。
好的代码应该是 simple and abstracts repeated patterns (DRY).
我认为 In-logic assignment 做到了。同样的还有 Object.tap
、Object.try
、Object.blank?
、 ||=
(这个可以叫做 memoizable assignment partten?) 还有 Rails 里的 find_or_create
方法。
这些都是为了解决实际问题而生的 Ruby Idoim。我用着很 happy,这是一个好特性。
呵呵,你举的例子很好啊。不过和你之前的说法自相矛盾... 那你说他们毫无例外的都没有加括号,这是谁错了呢?
如果一定让我两者选其一,我宁可选择你介绍的代码示例,反正不推荐的用法都用了,还加那两个括号干嘛?只要了解 Ruby 运算符的结合性,就会知道,几乎所有情况下,不加括号的表达式很少出错,因为一开始 Ruby 就是为不加括号而设计的。
但是如果让我自己写,我一定会写两行,因为写在一起除了可能会让你出错,没有任何好处可言。这是个条件表达式,又不是方法,或者 block, 这样的代码,在 if 语句内赋值,甚至会给我一个错觉,是不是声明了一个条件表达式内的本地变量??
, 如果不这样写法,我根本不可能有这样的错觉。
嗨~ 我又看了下咱俩的回帖,其实是我没明白你的意思。惭愧呀~
其实你一直在说一个方面,而我以为你一直在说另一个方面。哈哈。
我刚刚想了想,确实蛮有趣的。
foo[name] = value if 'name = value' =~ /(?<name>.*)\s*=\s*(?<value>.*)/
这个之所以无法实现,其实因为:在使用一个本地变量之前,这个本地变量必须首先被定义。而本地变量
的定义是在源码解析的过程中完成的。这就和下面的代码效果类似:
if false
x = 0
end
p x # => x = nil
在语法解析阶段,在使用本地变量 x 之前,解释器看到了 x = 0 这个赋值语句,首先初始化 x
这个变量为 nil ,虽然稍后没有具体执行 x = 0 对 x 进行赋值,但是这个 x 已经被初始化了。
上面那个正则匹配的示例,有点类似于下面这个示例:
p x if x = 0 # = > undefined local variable or method `x' for main:Object
之所以出错,是因为在源码解析阶段,运行 p x 的时候,这个 x 是不存在的。只有在运行 x = 0 之后,x 才是存在的。所以这个语句在执行阶段,看起来应该是这样的:p x if 0
而后面的有关$1,$2的那个示例,则不一样:
foo[$1] = $2 if 'name = value' =~ /(.*)\s*=\s*(.*)/
诸如 $1, $2 这些变量,在解释器一开始的时候,就已经被定义并初始化为 ni l . 然后在源码解析时,括号内的结果直接被赋值给之前定义的 $1, $2, 所以在执行时,$1, $2 就是可用的。
以上结论都是猜的,因为不懂 C, 也没办法验证,不妨请出 @skandhas , 能否单独开贴,或者在这里,给大概解释下,Ruby 解释器在解释一个 .rb 文件时,大概过程分为几个大的步骤。
BTW: @skandhas, 我发现可能我邮箱有些问题,给好些个人发邮件都没回复,我前阵子给你推荐了个 Emacs 插件,发到你 163 邮箱了,你是不是没收到?