新手问题 求教函数调用与 send 方法的问题

lilijreey · September 08, 2018 · Last by lilijreey replied at September 08, 2018 · 1381 hits

今天闲来写了个高阶函数

 def twice(fn, v)
  fn(fn(v)) # 调用时说没有定义fn 函数
 send fn , (send fn, v) # 这样OK
end

def appendX(str)
  str << 'X'
end

twice(:appendX, 'ooo') 
#1.为何只能使用send, 而直接调用会报错,也就是说
fn = appendX
fn('oo') 这样不行, 感觉不允许这样很不自然啊, 求大神解释原

fn = appendX()
fn('oo')

这代码怎么看怎么不对啊?

写错了,fn = method(:appendX)

Reply to pinewong

谢谢,但试了一下还是不对

def app(str)
   str << '!'
end

fn = method(:app)
fn('ooo') # error 这样还是不行为什么呀
fn.call('ooo') #ok

看来 ruby 的函数名并不是一个普通的符号或者变量名。这点和很多语言的不一样。

Reply to lilijreey

为什么有这样的结论?函数名就是变量啊

Reply to IChou

能举例子吗 如果是个变量那你能把他付给另一个变量吗?你能得到该变量的 class 吗

建议楼主花几分钟看一下基本的语法。这些地方和 Python 不一样的。

Ruby 调用方法可以省略括号,这就意味着:

  • foo.bar 必然是 foo.bar()
  • foo 可以是取局部变量也可以是 foo(), 就看这个局部变量有没有定义了
  • 你可以创建 lambda 或者 method 对象,像这样: -> x { x << 'str' }, method(:foo), obj.method(:foo)
  • lambda 或者 method 也是对象,调用它不是加括号而是用 call 或者 [] 或者 .()foo.call 1, 2

Ruby 对象不能直接接括号,能接括号都是方法调用。

回到你开始的代码,可以这么写 (用 Lambda 或者 Method):

def twice fn, v
  fn.(fn.(v))
end

append_x = -> str { str << 'X' }
twice append_x, 'ooo'

def append_x2 str
  str << 'X'
end
twice method(:append_x2), 'ooo'

也可以这么写 (用 symbol 或者字符串):

def twice fn, v
  send fn, (send fn, v) # 这时 fn 是 Symbol 或者字符串, 不是 Lambda 或者 Method 对象 
end

def  append_x str
  str << 'X'
end
twice :append_x, 'ooo'

下面的 Y combinator,留给楼主回去思考:

def Y &f
  g = -> h, x, *xs { f[h[h], x, *xs] }.curry
  g[g]
end

factorial = Y {|f, n| n == 0 ? 1 : n * f[n - 1] }
factorial[8]
You need to Sign in before reply, if you don't have an account, please Sign up first.