http://ruby-doc.org/docs/ProgrammingRuby/html/tut_containers.html
C:\Users\Administrator>irb
irb(main):001:0> def a(name)
irb(main):002:1> yield
irb(main):003:1> puts "hello"
irb(main):004:1> yield
irb(main):005:1> end
=> nil
irb(main):006:0> a("1")
LocalJumpError: no block given (yield)
from (irb):2:in `a'
from (irb):6
from C:/Ruby192/bin/irb:12:in `<main>'
irb(main):007:0> a("dd") do
irb(main):008:1* puts "z"
irb(main):009:1> end
z
hello
z
=> nil
irb(main):010:0> aa=a("dd") do
irb(main):011:1* puts "z"
irb(main):012:1> end
z
hello
z
=> nil
irb(main):013:0> aa=a("dd") do
irb(main):014:1* "z"
irb(main):015:1> end
hello
=> "z"
irb(main):016:0>
Ruby代码块是用大括号或者do...end括起来的一系列代码。
Ruby代码块贯穿在实现迭代器的Ruby库中,迭代器就是一种方法,用来连续返回某种集合的元素,比如一个数组。
块的真正的作用是当你创建了一个块之后,你就可以将它与函数联系在一起。你可以在调节器用函数的那一行代码之后加入一个块。
http://developer.51cto.com/art/200912/170500.htm
&block
使用
http://blog.codahale.com/2005/11/24/a-ruby-howto-writing-a-method-that-uses-code-blocks/
Background
Foreground
Link Color
Link Visited
Size:
Width:
More ▼
Open Mode
Overlay Original
Replace Original
推荐给好友收藏到IE收藏夹收藏到QQ书签收藏到百度收藏到Google
作者:追梦 来源:http://www.itrenjia.org 日期:2010-07-25 22:54:38 (共有0条评论)我要评论
第五章代码块和迭代器
§5.1 代码块(Block)
§5.1.1什么是代码块
在Ruby中在在大括号之间的代码或放在do/end之间的代码是一个代码块。代码块只能出现在一个方法的后边,它紧接在方法最后一个参数的同一行上
第五章代码块和迭代器
§5.1 代码块(Block)
§5.1.1什么是代码块
在 Ruby中在在大括号之间的代码或放在do/end之间的代码是一个代码块。代码块只能出现在一个方法的后边,它紧接在方法最后一个参数的同一行上。代码块的内容并不会被马上执行,当执行到被调用的方法时,解释器的运行时环境会记住代码块出现的现场,然后执行被调用的方法。
[1,2,3,4,5].each { |i|
puts i
}
[1,2,3,4,5].each do |i|
puts i
end
一般的使用习惯是:(to-do 具体解释)
l 当关心边际(side effect)效应时使用 do/end。
l 当关心返回结果应时使用大括号。
§5.1.2代码块与对象
代码块并不是对象,但可以方便的转化为Proc类的对象。有三种转化的方法:
l 将一个代码块传递给最后一个参数以&开始的方法。
def meth1(p1, p2, &block)
puts block.inspect
puts block.call
end
meth1(1, 2) { "This is a block" }
l 使用Proc.new方法,后边的参数为一个代码块:
block = Proc.new { "a block" }
l 调用Kernel.lambda方法:
block = lambda { "a block" }
前两种方法是等价的,而第三种方法,用 lambda 生成的 Proc 对象和用 Proc.new 生成的 Proc 对象之间是有差别的。这是一个微妙的差别,这个差别与 return 关键字相关。lambda 中的 return 从 lambda 返回。而 Proc 中的 return 从外围方法返回。
可以看以下两个例子:
def test_proc
p = Proc.new { return 1 }
p.call
puts "Never come here"
end
test_proc #=> 1
执行后"Never come here"不会被输出,执行p.call相当于在test_proc方法内执行了return语句。
def test_lambda
p = lambda { return 1 }
result = p.call
puts "The value is: #{result}"
end
test_lambda
执行后的结果为:
The value is: 1
可见使用lambda生成的Proc对象执行call方法调用时,return表示从lambda包围得块内返回。
在一个代码块中执行next语句会导致代码块返回。返回值就是next语句后带的参数。如果next后没有参数,那么返回值为nil。
def meth2
result = yield
"The block result is #{result}"
end
puts meth2 { next 9 }
pr = Proc.new { next 100 }
puts pr.call
pr = lambda { next }
puts pr.call
执行结果为:
The block result is 9
100
nil
§5.2 迭代器(Iterator)
§5.2.1什么是迭代器
简单的讲,一个迭代器就是一个能接受代码块的方法。当初为了进行迭代操作而设置了带块方法,所以现在它仍然常常被称作迭带器。
[1,2,3,4,5].each { |i|
puts i
}
上述代码中,each方法反复调用代码块,我们称each方法为一个迭代器。
迭代器(Iterator)即指调用带块方法。实际上,在早期版本的 Ruby 中,使用代码块的方法被称为迭代器,因为它们就是被设计来实现循环迭代的。但是在Ruby发展过程中,代码块的用途在后来已经得到了很大的增强,从最初的循环抽象到任何事情。可以将那些进行迭代操作的方法叫做迭代器,但如果将所有带块方法的调用过程都看作迭带器的话,并不合适而且概念上会引起混乱
§5.2.2使用迭代器
#一个使用迭代器的简单例子,数组中每一个元素作为参数执行其后的代码块
['This', 'is', 'a', 'dog'].each do |entry|
print entry, ' '
end
执行结果为:
This is a dog
#另一个使用迭代器的例子,代码块可以访问其外的数据
factorial = 1
1.upto(10) do |i|
factorial*= i
end
puts factorial
执行结果为:
3628800
#代码块的返回值可以被调用者使用
b = [1, 2, 3, 4, 5].map do |entry|
entry * entry
end
print b.inspect
执行结果为:
[1, 4, 9, 16, 25]
#代码块也可以使用一个以上的参数
result = (0..100).inject(0) do |sum, i|
sum + i
end
print result
执行结果为:
5050
§5.2.3 yield
在方法中可以使用yield来执行代码块的内容,就好像传入的代码块是这个方法的一部分一样。每当碰到一个yield调用,代码块的内容就会被执行一次。当代码块执行结束后,程序会回到yield的那一行继续向下执行。
def twoTimes
yield
yield
end
twoTimes { puts "Hello World!" }
执行结果为:
Hello World!
Hello World!
你可以使用yield操作传参数给一个代码块,并且从代码块取回返回值。
def fibonacii(max)
f1, f2 = 1, 1
while f1 <= max
yield f1
f1, f2 = f2, f1+f2
end
end
fibonacii(1000) { |f| print f, " " }
执行结果为:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
在这个例子中,yield接收一个参数,这个参数将会在执行的时候传递给指定的代码块。在代码块中,接收的参数使用两个竖线括起来放在代码块的头部。yield操作也可以有返回值,yield操作的返回值就是代码块中最后一个表达式的值。
§5.2.4 编写自己的迭代器
def factorial(count, &block)
value = 1
1.upto(count) do |i|
value = value * i
block.call(i, value)
end
end
factorial(5) do |i, sum|
puts "factorial(#{i}) = #{sum}"
end
执行结果为:
factorial(1) = 1
factorial(2) = 2
factorial(3) = 6
factorial(4) = 24
factorial(5) = 120
也可以将传入的代码块保存以供以后使用:
class Mathematics
def initialize(&block)
@block = block
end
def factorial(max)
value = 1
1.upto(max) do |i|
value = value * i
@block.call(value)
end
end
end
the_value = Mathematics.new do |count|
puts "Current value is #{count}"
end
the_value.factorial(5)
执行结果为:
Current value is 1
Current value is 2
Current value is 6
Current value is 24
Current value is 120
下一篇: 《Ruby》Ruby基本类型
http://www.itxuexi.com/tech/script/ruby/85561252680952.html
Background
Foreground
Link Color
Link Visited
Size:
Width:
More ▼
Open Mode
Overlay Original
Replace Original
2009-09-11 22:55:52 来源:脚本之家(www.jb51.net) 【大 中 小】 评论:0 条
-
一、方法
Ruby 的方法定义允许为参数设置默认值,不过在带有默认值的参数后面不能出现不带有默认值的参数(允许 * 和 &),也就是说下面的方法定义是不被允许的,解释时会出现 parse error。 还有一点与 C# 不同的是,方法定义不能出现在方法调用的后面。
# parse error def Display(args1="proshea", args2) end # 允许 def Display(args1="proshea", *args2) end # 允许 def Display(args1="proshea", &args) end Show() # 出现在 Show 调用之后是错误的 def Show end
Ruby 也支持 C# params 这样的参数功能, 只是 Ruby 用 * 标识罢了。
def Display(*args) print %Q~#{args.join("-")}~ end # proshea-32-WinForm Display("proshea", 32, "WinForm")
同样的, Ruby 也有类似于 C# delegate 的应用,只是更简单,直接用 & 来表示,并且 Ruby 用一个称为 yield 的关键字来知会解释器执行传入的代码块或者说 Proc object(过程对象?)。
1def Display(&block) 2 if block_given? 3 yield(block) 4 else 5 print %Q~没有传入过程对象~ 6 end 7end 8 9def Show() 10 print %Q~Show 方法调用~ 11end 12 13# 没有传入过程对象 14Display() 15# 在 Display 内部调用 Show 方法 16# 注意起始大括号仍然只能和方法名在同一行 17Display(){ 18 Show() 19}
block_given? 是被定义在内部模块 Kernel 当中的方法,用以表明是否传入了 Proc object。之后,Ruby 用 yield 通知解释器执行传入的 Proc。过程对象也可以带有参数,不同于普通方法的是过程对象的参数是位于一组 | | 之中。可以使用 Proc object 的 call 方法来调用带参数的过程对象。
1class Employee 2 def initialize(username, age, &block) 3 @username, @age, @block = username, age, block 4 end 5 6 def Display(txt) 7 # 虽然 @block 是个实例变量,但在此处一定要加上大括号 8 print "#{@block.call(txt)}: #@username-#@age" 9 end 10end 11 12emp = Employee.new("proshea", 32){ 13 |txt| 14 txt 15} 16emp.Display("context")
1
-
您看完这篇文章的心情是: <已有0人发表看法>
0
0
0
0
0
0
0
0
吃惊
欠揍
支持
很棒
一般
搞笑
扯淡
不解
相关文章列表
没有评论
推荐文章
-
发布时间
2008-27-09 04:06
浏览数量
811
回复数量
1
收藏数量
0
shitou 2 年之前
面向对象的思想在ruby中表现的淋漓尽致,几个特性也是比较难以理解的,这里做个小总结:
1. super
先看例子吧:
class Father def hello p 'hello, i am dad' end end class Child < Father def hello p 'hello, i am son' super end end Father.new.hello #hello, i am dad Child.new.hello #hello, i am dad #hello, i am son
ruby类中方法查找路径为:类实例先查找本类中是否定义了该方法, 然后查找该类中是否include了其他module,该mudule中是否包含了改方法, 然后查找该类的父类中是否有改方法, 然后是父类中是否include了其他module,改mudole中是否包含了其他方法。
在查找的整个过程中如果查找到将会立刻执行并停止向上一级的查找
super可以理解为,按照上面的查找路径再向上一级进行查找, 如果有,就在该处(调用super的逻辑片段中)再执行一遍改匹配该方法名的方法,如果整个查找过程都没有匹配到,将会抛出异常 NoMethodError,所以上面的例子就不难理解了, 要注意的是super不是只查找自己父类中的同名方法, 包括module的
另外super也接受参数:
super, 及没有加任何参数时(裸词), 是默认自动向前传递所有该方法所获得的参数
super(), 不向上一级传递任何参数
super(a,b,c), 传递指定的参数
2. <<
<<用来批量定义类或者模块的方法(注意不是实例方法)
下面两段代码的效果是一样
class As def As.hello #do something end end class As class << self def hello #do something end end end
同理下面两段代码的效果是一样的
module TimeFormat def self.show_time #do something end end module TimeFormat class << self def show_time #do something end end end
3. yield和block
block在ruby是独有的特性, 其中yeild的使用更是灵活
下面是内置类File :pen的源码
def File.open(name, mode = "r") f = os_file_open(name, mode) if block_given? begin yield f ensure f.close end return nil else return f end end
这个方法非常简洁明了,block_given?判断是否传递了代码块,有的话就把文件句柄传给代码块进行操作,这个地方就是
yield f
我觉得可以这样理解yield的行为:把yield后面的参数传递给后面的代码块作为参数。
yield的作用可以这样理解:拿学生举个例子,每个学生交的学费是一样的,所以处理交学费的流程就放在方法中,但是每个学生的要花费的生活费不一样,要考虑很多的因素,所以把特殊的因素放在代码块中操作,这样就可以即统一又有区别的计算出总的花费。
另一个例子
def c(v, &block) return v unless v.is_a? Array v.each &block if block_given? end c([1,2,3]) { |x| p x + 1 } #2, 3, 4 def c(v) return v unless v.is_a? Array v.each { |x| yield x } if block_given? end c([1,2,3]) { |x| p x + 1 } #2, 3, 4
[ 本帖最后由 shitou 于 2008-9-27 12:08 编辑 ]
理解了上面的,当你想往rails的model中添加自己的类方法或者重写内置方法时就可以
class << ActiveRecord::Base def your_action #do something end end
[ 本帖最后由 shitou 于 2008-9-27 12:17 编辑 ]
在回复之前你需要先进行登录
账户或邮箱
密码
记住我的登录状态 (忘记密码)
© 2008-2011 Kohana 中文
Rendered in 0.76981秒. Powered by Alpaca