方法

定义

通过 def 来定义方法

def factorial(n)
  if n < 1
    raise "argument must be > 0"
  elsif n == 1
    1
  else
    n * factorial(n - 1)
  end
end

如果一个方法正常的结束,最后一个表达式的值就是方法的返回值,Ruby 可以有多个返回值

def polar(x, y)
  return Math.hypot(y, x), Math.atan2(y, x)
end

distance, theta = polar(x, y)

定义单例方法,在单个对象上定义的方法

o = "message"

def o.printme
  puts self
end

o.printme

别名

alias 定义一个已有方法的别名

alias aka also_known_as

参数默认值

可以像如下给方法参数添加默认值

def prefix(s, len = 1)
  s[0, len]
end

默认值可以是任意的表达式,默认值是方法在被调用的时候才赋值给参数的

def suffix(s, index = s.size - 1)
  s[index, s.size - index]
end

任意长度参数

在方法参数名前添加 *,可以接受任意长度的参数,这些参数都会变成参数数组

def max(first, *rest)
  max = first
  rest.each { |x| max = x if x > max }
  max
end

max(1)       # first = 1, rest=[]   
max(1, 2)    # first = 1, rest=[2]  
max(1, 2, 3) # first = 1, rest=[2, 3]

可以用 * 来打散数组,范围,或枚举变成独立的方法参数

data = [3, 2, 1]
m = max(*data) # first = 3, rest=[2, 1] => 3

命名参数

用哈希来做命名参数

def sequence(args)
  n = args[:n] || 0
  m = args[:m] || 1
  c = args[:c] || 0

  a = []
  n.times { |i| a << m * i + c }
  a
end

sequence({ :n => 3, :m => 5 }) # => [0, 5, 10]

块参数

在方法定义的最后一个参数前加 &,这个参数会指向块

def sequence3(n, m, c, &b)
  i = 0
  while(i < n)
    b.call(i * m + c) 
    i += 1
  end
end

sequence3(5, 2, 2) { |x| puts x }

在方法调用时,& 用在 Proc 对象前,就像普通方法调用后面跟的块一样

a, b = [1, 2, 3], [4, 5]
sum = a.inject(0) { |total, x| total + x } # => 6
sum = b.inject(sum) { |total, x| total + x } # => 15

# 上的代码,可以转换为下面这样

a, b = [1, 2, 3], [4, 5]
summation = Proc.new { |total, x| total + x }
sum = a.inject(0, &summation) # => 6
sum = b.inject(sum, &summation) # => 15

Proc,Lambda 和 闭包

创建 Proc

p = Proc.new { |x, y| x + y }

创建 lambda

is_positive = lambda { |x| x > 0 }

succ = ->(x){ x + 1 } # Ruby 1.9 中的新定义方法

调用 Proc 或 Lambda

通过 Proc 类定义了 call 方法来调用

succ.call(2) # => 3

闭包

如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被定义为闭包 。定义在外部函数内的但由内部函数引用或者使用的变量被称为自由变量,注意 lambdaproc 中使用的变量不是在创建 lambdaproc 的时候就静态绑定了,而是动态绑定的,变量的值是在 lambdaproc 被调用的时候才进行查找的

def accessor_pair(initialValue = nil)
  value = initialValue
  getter = lambda { value }
  setter = lambda { |x| value = x }
  return getter, setter
end

getX, setX = accessor_pair(0)
puts getX[] # Prints 0
setX[10]
puts getX[] # Prints 10