函数
代码块
在Ruby中一个代码块就是把几个Ruby语句打包到一起
如{puts "hello"}和
do
club.enroll(person)
person.socialize
end
block_given?
判断是否已经给出一个快,这样方法可以有两个行为
传递块对象
一个块是一个Proc对象,使用call方法可以调用这个块对象
1.在向方法传递时要用&做作为前缀,这时Ruby会把块默认转换为Proc对象
class ProcExample
def pass_in_block(&action)
@stored_proc = action
end
def use_proc(parameter)
@stored_proc.call(parameter)
end
end
eg = ProcExample.new
eg.pass_in_block { |param| puts "The parameter is #{param}" }
eg.use_proc(99)
2.注意:虽然快对象出现在参数列表中,但是调用的时候并没有显示传递块
3.块对象必须出现在最后
4,在传递块对象的时候要加上&
例如:
def math(a, b)
yield(a, b)
end
def teach_math(a, b, &operation)
puts "Let's do the math:"
puts math(a, b, &operation)
end
teach_math(2, 3) {|x, y| x * y}
arity
得到Proc对象的参数个数
作用
一个语句块可以在函数调用是传递给函数,在函数内部可以用yield调用传递给这个函数的代码块。还可以给yield传递参数,而代码块接受参数的形式如下:
{|person, phrase| puts "#{person} says #{phrase}"}
代码块相当于匿名函数。
load pattern
这个同scala一致
闭包
1.闭包的真正意义是:块中包含了块可以访问的本地的变量,然后传递快时就可以一起传递这些变量。这样,这些本地变量也随着块一起在程序中传递。
def n_times(thing)
lambda {|n| thing * n }
end
2.代码块可以和调用函数以外的数据发生联系
sum = 0
[1, 2, 3, 4].each do |value|
square = value * value
sum += square
end
puts sum
注意:这人的代码块用了 外界的变量sum
如果想要控制sum是快内的变量,那么就要在参数后面设定
[1, 2, 3, 4].each do |value;sum|
square = value * value
sum += square
end
lambda
1.声明lambda时要用lambda函数
2.从Ruby1.9开始可以用另外的方法创建Proc对象
proc1 = ->arg { puts "In proc1 with #{arg}" }
proc2 = ->arg1, arg2 { puts "In proc2 with #{arg1} and #{arg2}" }
proc3 = ->(arg1, arg2) { puts "In proc3 with #{arg1} and #{arg2}" }
proc1.call "ant"
proc2.call "bee", "cat"
proc3.call "dog", "elk"
3.在Ruby1.9中,可以用另外的方法调用Proc对象
1.proc[arg-list]
2.proc.(arg-list)
控制结构
一个块可以用yield调用,也可以把他传递给方法的最后一个参数。前一种方法调用形式如下: ri("ssj") {p "start"},这种情况不能和Ruby的风格兼容(尽管在其他的语言中看起来很自然)。而后一中方法调用形式是:after i { puts i},更加自然。
定义如下:
def after(seconds, &block)
Thread.new do # In a new thread...
sleep(seconds) # First sleep
block.call # Then call the block
end # Return the Thread object right away
end
可以利用这一点来创建控制结构
Proc和lambda的不同
Proc.new和Kernel.proc用来产生块,Kernel.lambda用来产生lambda函数。
return
Proc中的return会在块定义的地方返回,可以不用显式的return来避免这个问题;lambda则仅仅从块中返回,表现的像一个函数。因此在需要传递时,应该常常使用lambda。
as:
def procBuilder(message) # Create and return a proc
Proc.new { puts message; return } # return returns from procBuilder
# but procBuilder has already returned here!
end
def test
puts "entering method"
p = procBuilder("entering proc")
p.call # Prints "entering proc" and raises LocalJumpError!
puts "exiting method" # This line is never executed
end
test
对于lambda,则不同
def lambdaBuilder(message) # Create and return a lambda
lambda { puts message; return } # return returns from the lambda
end
def test
puts "entering method"
l = lambdaBuilder("entering lambda")
l.call # Prints "entering lambda"
puts "exiting method" # This line is executed
end
test
如果块在顶层空间中定义。那么return出现就会引发错误,因为没办法从顶层空间返回。
def double(callable_object)
callable_object.call * 2
end
p = Proc.new { return 10 }
# This fails with a LocalJumpError:
# double(p)
break
1.Proc中,一旦break就会跳出block。并且导致迭代器返回。
2.在lambda中,如果没有任何循环或者迭代,那么break就不会起作用。
参数个数
Proc对于传递的参数个数比较宽松,参数多或者少都可以调用Proc;lambda则不同
定义
def say_goodnight(name)
result = "Good night, " + name
return result
end
注意函数的返回值是最后一个表达式的值,因此可以不用写return语句
简写
1,Ruby中方法在声明和使用时可以去掉圆括号,仅仅以空格代替
2,当映射表是函数的最后一个参数,是这时候可以去掉大括号。而仅仅写其中的内容
3,当参数是可变的时,可以去掉圆括号写成print_sym :a,:b,:c,这样就非常像一个关键字了。
方法名
1.一个普通方法一般是以小写字母开头,一般大写开头的方法用来类型装换
2.返回boolean的值得方法以?结尾
3.一些危险的方法以!结尾,比如会更改对象状态的方法
4.
默认参数
Ruby可以使用默认参数,一般其规则和C++一致,即默认参数字字可以在参数列表的最后出现。但是ruby并不要求一定要这样,必要时可以使用命名参数来简化参数传递。
可变参数
def greeting(*name,age)
puts "hello,#{name.count},you are #{age} years old"
end
不想Scala那样,ruby的可变参数可以出现任何位置,不仅仅是在参数列表的末尾,而且从理论上,在任何地方支持默认参数都是可以的。
1.可变参数只能出现一次
2.在可变参数后面不能有默认参数
3.可变参数在方法中是一个列表
多返回值
def meth_three
100.times do |num|
square = num*num
return num, square if square > 1000
end
end
meth_three # => [32, 1024]
如果不带return则必须用如下形式
def polar(x,y)
theta = Math.atan2(y,x)
r = Math.hypot(x,y)
[r, theta]
end
单例方法
动态添加对象方法
在一个对象上定义方法就可以实现动态向对象添加方法
例如:
o = "message"
def o.print_self
p self
end
o.print_self#"message"
Ruby中所有的属性都是私有的,因此Ruby会把所有的调用都看成方法,因此没办法向对象添加属性,只能添加方法。再进一步:Ruby的对象就像一个对象槽,其中可以像一个Hash那样添加元素
类方法(静态方法)
在对类和模块定义单例方法时,就是类方法
参见: 类方法
undef
def sum(x,y); x+y; end
puts sum(1,2)
undef sum
方法重命名
方法重命名在Ruby中有两个作用
as:alias original_hello hello
1.给一个方法多个名称,那么就可以在合适的地方使用更加合适的名字
2.一旦一个类的实例方法被重命名了,那么原来的命字就可以重新使用。这个在开放类中特别好有用,因为有时开放类中要改变类的实例方法,这时,只要把原来的方法重命名就可以。
as:
def hello # A nice simple method
puts "Hello World" # Suppose we want to augment it...
end
alias original_hello hello # Give the method a backup name
def hello # Now we define a new method with the old name
puts "Your attention please" # That does some stuff
original_hello # Then calls the original method
puts "This has been a test" # Then does some more stuff
end
注意:alias是一个关键字,因此这个调用没有用逗号隔开
Method
创建:
m = 0.method(:succ) # A Method representing the succ method of Fixnum 0
String.instance_method(:reverse) # => UnboundMethod object
调用:
m[],或者m.call
转换成Proc
1.Method.to_proc
2.def square(x); x*x; end
puts (1..10).map(&method(:square))
参见: 方法 (相同)
Unbound Method
未绑定方法不同于绑定方法,他们在调用时必须首先绑定一个对象
创建:
1.unbound_plus = Fixnum.instance_method("+")
2.unbound_plus = Fixnum.public_instance_method("+")
绑定:
plus_2 = unbound_plus.bind(2) # Bind the method to the object 2
调用:绑定后变成Method,因此可以同Method
函数式编程
1.Ruby中函数是一等公民,函数可以相互传递,同时也支持闭包
偏函数
product = lambda {|x, y| x*y } # A function of two arguments
double = lambda {|x| product(2,x) } # Apply one argument