Ruby 中关于block的一些总结

2017-11-11 11:42:21来源:oschina作者:穿山人点击

分享

在Ruby中块是重点也是难点下面我把这两天学习当中的遇到的知识点做了一些总结。


# 1.1block可以用来做循环
array = %w(This is my blog about Ruby)
array.each{|x| print x + " "}
# 1.2块变量也同样适用多重赋值规则
hash = {x: 'this', y: 'why', z: 'i/'m'}
hash.each{|key, value| print [key,value]}
# 2.1块可以隐藏常规处理
file = File.open("sample.txt")
file.each do |line|
print line
end
file.close #读取完文件后要将通道关闭,不然会造成IO堵塞
# 2.2 File.open方法中使用块时,在块内部处理完并跳出方法之前文件会自动关闭,这个也是块给我们做的
File.open("sample.txt") do |file|
file.each_line do |line|
print line
end
end
# 2.3上面的代码类似于下面的代码
file = File.open("sample.txt")
begin
file.each_line do |line|
print line
end
ensure
file.close
end
# 3.1可以替换部分算法
# 使用默认sort方法时没有指定块的时候默认用<=>进行比较
str = %w(This is test about block)
p str.sort
#两者效果相同
p str.sort{|a, b| a <=> b}
#可以通过块来自定义排序
p str.sort{|a, b| a.length <=> b.length}
# 使用sort_by时候先将所有的元素使用length 然后再排序 这样不像上面每调用一次块要执行两次length方法
p str.sort_by{|item| item.length <=> item.length}
# 4.1 定义带块的方法
#使用yield 没有带参数
def foo
a = 1
yield a
end
foo {|x| puts x + 2}
#带参数
def foo2 b
a = 2 * b
yield a
end
foo2(2){|x| puts x}
#使用 & 和 call 以参数的形式使用块
def bar(&block)
a = 3
block.call a
end
bar{|x| puts x**2}
#如果有多个参数的时候 &block 这种类型的参数称为Proc参数
# ruby会把传进来的&block 块封装成Proc对象 这样使用call方法的时候就
#相当于对象调用方法
def bar2(a, b, &block)
block.call(a, b)
end
bar2(2,'x'){|c, d| puts [c, d]}
# 控制块的执行
# 首先要明确一点break 终止最内部的循环。如果在块内调用,则终止相关块的方法(方法返回 nil)
arry = %w(test hahah in ruby)
def test_break arry
i = 1
arry.each do |str|
print [i, str]
break if i == 3
i += 1
end
print '测试普通break'
end
test_break arry #break终止循环但还是会执行 print '最后再输出一次'
# 下面测试下break在代码块中
def test_break2 arry
i = 1
arry.each do |str|
puts str
yield i
i += 1
end
print '测试在block中break'
end
#break在块内则终止相关块的方法 并且可以选择返回参数 此处返回0
p test_break2(arry){|x| break 0 if x == 3}
# next跳到循环的下一个迭代。如果在块内调用,则终止块的执行(yield 表达式返回 nil)。
ary = %w(i l x c b d next)
def test_next arry
i = 1
arry.each do |x|
i += 1
next if i == 2
print i,x
end
print '我是来测是next的'
end
test_next ary
puts ">>>>>>>>>>>>>>>>>"
def test_next2 arry
i = 1
arry.each do |x|
p yield i, x
i += 1
end
print '测试块内的next'
end
#此处当i=2 时候终止块的执行 就是此次yield的返回值为自定义 但 yield下面的i += 1继续执行
test_next2(ary) do |a, b|
next "test success" if a == 2
print a,b
end
# 在块中的return 不是return出代码块 而是return出包含这个代码块的方法
# 重点因为block是代码的集合不是方法
def test_return
i = 3
yield i
print '方法的return'
end
test_return do |x|
print "我是块中的return 我要return出去了"
return if x == 3
end
# 块变量可以多重赋值
def block_args_test
yield()
yield(1, 2)
yield(1, 2, 3)
end
#通过一个变量来接收
block_args_test{|a| p [a]}
#通过三个变量来接收
block_args_test{|a, b, c| p [a,b,c]}
#通过|*a|来接受 将所有块变量整合成数组来接收
block_args_test{|*a| p a}
# 将块封装成对象
# 上面我们说过了可以按一下方式将块做为参数
# 因为&参数名 ruby会自动传进来的块封装成Proc对象 称为Proc参数
# 然后通过调用对象的call 来执行代码块的内容
def foo(&block)
block.call
end
foo{puts '测试一下'}
#定义一个Proc对象 并调用
#两个方法一个是 Proc.new
hello = Proc.new do |name|
puts "hello i am #{name}"
end
hello.call('ruby')
#proc方法指定块
hello2 = proc do |x|
print "hello i am #{x}"
end
hello2.call('Java')
#Proc参数一定要放在参数列表的最后一位
def call_each(arry, &block)
arry.each(&block)
end
call_each(1..4){|n| puts n**2}
# Proc 是能让块做为对象在程序中使用的类
proc = Proc.new {|x| x * 2}
p proc.class
p proc.call(5)
lambda = lambda {|x| x * 2}
p lambda.class #也是proc类
#为何Porc有两个对象 proc和lambda 区别在何处
# 一个中心思想 两大区别
# 都是Proc的实例
# 但proc的行为更像block lambda的行为更像方法
# 区别一 调用时的参数 个数
p p = Proc.new {|x, y| p x,y}
p p.call(1)
p p.call(1, 2)
p p.call(1, 2, 3)
l = lambda {|x,y| p x, y}
# l.call(1) #会报错
p l.call(1, 2)
# p l.call(1, 2, 3) 也会报错
#因为在定义method时候你定义几个变量就传入几个变量 传多传少都会报错
#但block 但如果参数少就nil 补全 多的话就无视
# 区别2
p = Proc.new {|x| return if x > 0}
p p.call(1) #会报错因为此block没有被方法包围 所以无法return出方法
l = lambda {|x| return if x > 0}
p l.call(1) #但lambda就可以被return 因为他的行为更像method
#有些对象有to_proc方法 如果对象以"&对象"的形式传递参数
# 对象.to_proc就会自动被调用 进而生成Proc对象
# 其中符号 Symbol.to_proc方法比较典型
# & 把符号 :capitalize 生成Pro对象
# Proc.new do |arg|
# arg.capitalize
# end
p arr = %w(a b c)
arr.map(&:capitalize)
#使用符号来代替方法
p "a".capitalize
#method => proc => 利用& 才转成block
p arr.map {|x| x.capitalize }
#附上map each的区别
# each:连续遍历集合中的所有元素,并做相应的操作,原集合本身不会发生变化。
# map: 从集合中获取每个元素,并且传递给块,结果会返回新的数组,原集合发生变化
# collect: 类似于map
# inject:遍历整个集合,并且将集合中的元素,按照一定的方式累计,最后返回一个新的元素,原集合本省不会发生变化。

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台