Ruby Ruby 方法的执行结果默认为 “最后一条语句的结果”*3 (重要的事情要说三遍!)

winter · 2015年08月24日 · 最后由 douxiance 回复于 2015年08月27日 · 3426 次阅读

如题所术,这是个没有人再以为它是真理的真理了,谁不知道啊!可我这个不长记性的,一个坑里滚了好多次了。

def fn (arg)
    arg
    0 if arg < 0
end

p fn(2)
p fn(-1)

你猜结果是啥?好吧,可能就我不知道吧,还在这故弄玄虚。

nil  
0

我理解的“最后一条语句”一直和 ruby 理解的“最后一条语句”不是同一个语句,思想还是有点感性,ruby 他说了:我返回的是最后一条语句,那就是最后一条,即使是 if 判断错误没有进入 if 块里,那 if 判断就是我的最后一条。🙏

每次遇到要这样写的方法,都会扑通栽进这个坑里,发现问题后我每次都是这样解决的:

def fn (arg)
    return 0 if arg < 0
    arg   
end

当然针对这个例子三目运算符就可以,但有时其中的逻辑并不是这么简单的啊,还有其他什么妙招吗?

注:此贴目的主要有俩,1.在此立个碑,长个记性,以后不要再掉坑里了;2.破个处,我也算发过贴了,做了个爱噢贼(LZ)

逗比结束!😄

  1. if 表达式是有返回值的,你这里的 nil 和 0 恰恰是这个 if 表达式的返回值
  2. 你这个可以这样写:
def fn (arg)
    if arg < 0
      0
    else
      arg
    end
end

3 . ruby 方法的执行结果默认为最后一条语句的结果这句并不完全正确。以等号结尾的方法是特殊情况:

def name=(a)
  @a = a
  a * 2
end

result = (self.name= 'hello') 
result #=> 'hello'

#2 楼 @hooopo 你这个是因为根本没有调用吧?

#3 楼 @martin91 是的,,,编辑了一下...

标题很无聊。

你对自己说三遍好了为什么要对别人说多余的那两遍...

@luikore 额。。。好吧,我只是要说三遍,没有说对谁说啊。。。😅

@rei 现在标题只有无聊了 没有“很”了吧😳

返回值的提醒是有用的,很多人容易忽视。

最好是这样写

def fn (arg)
    arg = 0 if arg < 0
    arg   
end

另外我现在项目里规定必须把返回的内容写在函数最后一行,这样增加可读性

#10 楼 @zj0713001 这种函数肯定是三元表达式最好。 arg < 0 ? 0 : arg

#11 楼 @msg7086 恩 我只是按照他的习惯给出的例子

#12 楼 @zj0713001 其实最好的是 [0, arg].max ……

学习了,if 返回值和=号规则,

@48hour 额。。。等号啥规则?

#15 楼 @winter 参见@hooopo的回复,以等号结尾的方法的返回值的特殊性

@48hour 那是因为最后执行的不是“name=”方法,而是执行的变量赋值的表达式,@martin91 是正解

#3 楼 @martin91 印象中 send 是不走 assign 的,assign 的返回值必定是 assign 的值 但 send 的返回值是那个函数的返回值

@geniousli 好“坑” 😄

@cicholgricenchos 是否可以给些更进步的说明,这块一点尚未解除。

#21 楼 @douxiance

require 'ripper'
require 'pp'

def test=(n)
  2
end

code1 = "self.test=1"
code2 = "self.send(:test=, 1)"

p eval code1 # =是assign,返回值永远是用于assign的值
p eval code2 # send是方法调用,调用test=方法,返回值就是这个方法的返回值

# 两段代码解析后的语法树,详见《Ruby Under A Microscope》
pp Ripper.sexp(code1)
pp Ripper.sexp(code2)

@cicholgricenchos 补充一下我运行的结果,这下算是明白了,多谢!关于 assign 和方法调用这个我再去研究下。

1 2 [:program, [[:assign, [:field, [:var_ref, [:@kw, "self", [1, 0]]], :".", [:@ident, "test", [1, 5]]], [:@int, "1", [1, 10]]]]] [:program, [[:method_add_arg, [:call, [:var_ref, [:@kw, "self", [1, 0]]], :".", [:@ident, "send", [1, 5]]], [:arg_paren, [:args_add_block, [[:symbol_literal, [:symbol, [:@ident, "test=", [1, 11]]]], [:@int, "1", [1, 18]]], false]]]]]

Process finished with exit code 0

需要 登录 后方可回复, 如果你还没有账号请 注册新账号