进程和块
下面的方法会输出 Hello两次 。
def twice # 使用yield关键词定义块方法,编译器可以识别到
yield
yield
end
twice do
puts "Hello!" # 块代码
end
# 更加直观的写法, 使用 &
def twice(&block)
yield
yield
end
调用块方法使用 do…end 或 {}, 两者一般情况下是等价的。
twice() do
puts "Hello!"
end
twice do
puts "Hello!"
end
twice { puts "Hello!" }
区别在于 do…end使用left most模式, {}使用right most模式。
foo bar do
something
end
# The above is the same as
foo(bar) do
something
end
foo bar { something } # same as : foo(bar { something })
# 多个参数 , 实际传入的参数入量可以少于yield后面的参数数量
def many
yield 1, 2, 3
end
many do |x, y, z|
puts x + y + z
end
# 单参数调用简写
method do |argument|
argument.some_method
end
# 同上
method &.some_method
method &.some_method(arg1, arg2)
# 操作符也行。。。
method &.+(2)
method &.[index]
# 类型限制
def transform_int(start : Int32, &block : Int32 -> Int32)
result = yield start
result * 2
end
transform_int(3) { |x| x + 2 } #=> 10
transform_int(3) { |x| "foo" } # Error: expected block to return Int32, not String
# break ...略
# next ...略
# with...yield ...略
# 块参数展开, 块代码参数可以被小括号展开
array = [{1, "one"}, {2, "two"}]
array.each do |(number, word)|
puts "#{number}: #{word}"
end
# 上面的等价代码
array = [{1, "one"}, {2, "two"}]
array.each do |arg|
number = arg[0]
word = arg[1]
puts "#{number}: #{word}"
end
捕获(生成)块
块代码可以转换成一个带有上下文的进程。必须把块当成一个方法的block参数并指定其输入输出的参数类型。
def int_to_int(&block : Int32 -> Int32)
block
end
proc = int_to_int { |x| x + 1 }
proc.call(1) #=> 2
# 不指定返回类型,将没有返回
def some_proc(&block : Int32 ->)
block
end
proc = some_proc { |x| x + 1 }
proc.call(1) # void
# 使用下划线 返回任意类型值
def some_proc(&block : Int32 -> _)
block
end
proc = some_proc { |x| x + 1 }
proc.call(1) # 2
proc = some_proc { |x| x.to_s }
proc.call(1) # "1"
注: return和break不能使用在block中。
Proc字面量
def some_proc(&block : Int32 -> Int32)
block
end
x = 0
proc = ->(i : Int32) { x += i } # 字面量
proc = some_proc(&proc)
proc.call(1) #=> 1
proc.call(10) #=> 11
x #=> 11
# 进程也可以从现有的方法创建
def add(x, y)
x + y
end
adder = ->add(Int32, Int32)
adder.call(1, 2) #=> 3
块的转发执行
在yield可用的情况下,应避免使用闭包写法。并且break,next在捕获的闭包中无法使用。
# 使用yield进行转发
def foo
yield 1
end
def wrap_foo
puts "Before foo"
foo do |x|
yield x
end
puts "After foo"
end
wrap_foo do |i|
puts i
end
# 使用闭包转发, 效率会降低
def foo
yield 1
end
def wrap_foo(&block : Int32 -> _)
puts "Before foo"
foo(&block)
puts "After foo"
end
wrap_foo do |i|
puts i
end
闭包
捕获块和proc字面量隔离self和本地变量形成闭包,下面的例子来说明
x = 0
proc = ->{ x += 1; x }
proc.call #=> 1
proc.call #=> 2
x #=> 2
也可以是在方法中返回一个进程
def counter
x = 0
->{ x += 1; x }
end
proc = counter
proc.call #=> 1
proc.call #=> 2
# 上面的代码, x被proc字面量捕获并放置于堆中作为proc的上下文。一般情况下本地变量被放入栈中 并且在方法结束时被释放。
别名
使用别名可以给类型指定一个其它名字, 用于方便书写。
alias PInt32 = Pointer(Int32)
ptr = PInt32.malloc(1) # : Pointer(Int32)
#
alias RecArray = Array(Int32) | Array(RecArray)
ary = [] of RecArray
ary.push [1, 2, 3]
ary.push ary
ary #=> [[1, 2, 3], [...]]
当前内容版权归 crystal-lang中文站 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 crystal-lang中文站 .