是Ruby';s代码块与C#和#x27相同;什么是lambda表达式?

是Ruby';s代码块与C#和#x27相同;什么是lambda表达式?,c#,ruby,C#,Ruby,这两件事本质上是一样的吗?他们看起来很像我 lambda表达式是否借用了Ruby的思想?不完全如此。但它们非常相似。最明显的区别是,在C#中,lambda表达式可以到达任何可能有一个值恰好是函数的地方;在Ruby中,每个方法调用只有一个代码块 他们都借鉴了(一种可追溯到20世纪50年代末的编程语言)的思想,而后者又借鉴了20世纪30年代发明的lambda概念。Ruby实际上有4种结构,它们都非常相似 街区 blocks背后的思想是一种实现真正轻量级战略模式的方法。块将在函数上定义一个协程,函数可

这两件事本质上是一样的吗?他们看起来很像我


lambda表达式是否借用了Ruby的思想?

不完全如此。但它们非常相似。最明显的区别是,在C#中,lambda表达式可以到达任何可能有一个值恰好是函数的地方;在Ruby中,每个方法调用只有一个代码块


他们都借鉴了(一种可追溯到20世纪50年代末的编程语言)的思想,而后者又借鉴了20世纪30年代发明的lambda概念。

Ruby实际上有4种结构,它们都非常相似

街区 blocks背后的思想是一种实现真正轻量级战略模式的方法。块将在函数上定义一个协程,函数可以使用yield关键字将控制委托给该协程。在ruby中,我们几乎所有的东西都使用块,包括几乎所有的循环结构,或者在c#中使用
的任何地方。块之外的任何内容都在块的作用域内,但是相反的结果不是真的,除非块内部返回将返回外部作用域。它们看起来像这样

def foo
  yield 'called foo'
end

#usage
foo {|msg| puts msg} #idiomatic for one liners

foo do |msg| #idiomatic for multiline blocks
  puts msg
end
def foo(&block)
  return block
end

b = foo {puts 'hi'}
b.call # hi
class Symbol
  def to_proc
    Proc.new { |obj, *args| obj.send(self, *args) }
  end
end
过程 proc基本上是获取一个块并将其作为参数传递。这种方法的一个非常有趣的用途是,您可以传入一个proc,以替换另一个方法中的块。Ruby有一个特殊的proc强制字符,即&,并且有一个特殊的规则,即如果方法签名中的最后一个参数以&开头,它将是方法调用块的proc表示。最后,还有一个名为
block\u gived?
的内置方法,如果当前方法定义了块,它将返回true。看起来像这样

def foo
  yield 'called foo'
end

#usage
foo {|msg| puts msg} #idiomatic for one liners

foo do |msg| #idiomatic for multiline blocks
  puts msg
end
def foo(&block)
  return block
end

b = foo {puts 'hi'}
b.call # hi
class Symbol
  def to_proc
    Proc.new { |obj, *args| obj.send(self, *args) }
  end
end
更深入地说,rails在Symbol中添加了一个非常巧妙的技巧(并在1.9中被合并到核心ruby中)。基本上,强制通过对它旁边的任何对象调用
来实现它的魔力。所以rails的伙计们在#进程中添加了一个符号#,它可以调用传入的任何东西。这使您可以为任何聚合样式的函数编写一些非常简洁的代码,这些函数只是在列表中的每个对象上调用一个方法

class Foo
  def bar
    'this is from bar'
  end
end

list = [Foo.new, Foo.new, Foo.new]

list.map {|foo| foo.bar} # returns ['this is from bar', 'this is from bar', 'this is from bar']
list.map &:bar # returns _exactly_ the same thing
更高级的东西,但在我看来,这确实说明了你可以用proc实现的魔法

兰博达斯 lambda在ruby中的用途与在c#中的用途几乎相同,这是一种创建内联函数以传递或在内部使用的方法。与块和过程一样,lambda是闭包,但与前两个不同,它强制执行arity,并且从lambda返回将退出lambda,而不是包含范围。通过将块传递给lambda方法或ruby 1.9中的->来创建一个

l = lambda {|msg| puts msg} #ruby 1.8
l = -> {|msg| puts msg} #ruby 1.9

l.call('foo') # => foo
方法 只有认真的ruby极客才真正理解这一点:)方法是一种将现有函数转换为可以放入变量中的函数的方法。通过调用
method
函数并传入一个符号作为方法名,可以得到一个方法。你可以重新绑定一个方法,如果你想炫耀的话,你也可以强迫它进入一个进程。重写前面方法的一种方法是

l = lambda &method(:puts)
l.call('foo')
这里发生的事情是,您正在为puts创建一个方法,将其强制到一个proc中,并将其作为lambda方法块的替换传递进来,而lambda方法反过来会返回lambda


请随意询问任何不清楚的事情(在没有irb的情况下,在一个工作日很晚才写这篇文章,希望这不是纯粹的胡言乱语)

编辑:在评论中回答问题

list.map&:bar我可以使用此语法吗 代码块占用的时间超过 一个论点?假设我有hash={0=> “你好”,1=>“世界”},我想 选择以0作为目标的元素 钥匙也许不是一个好例子布莱恩 沈

这里有点深入,但要真正理解它是如何工作的,您需要了解ruby方法调用是如何工作的

基本上,ruby没有调用方法的概念,发生的事情是对象相互传递消息。您使用的
obj.method arg
语法实际上只是围绕更显式的形式,即
obj.send:method,arg
,在功能上等同于第一个语法。这是语言中的一个基本概念,也是为什么像
method\u missing
respond\u to?
这样的事情是有意义的,在第一种情况下,您只是在处理一条无法识别的消息,而在第二种情况下,您正在检查它是否正在侦听该消息

要知道的另一件事是相当深奥的“splat”操作符,
*
。根据它的使用地点,它实际上做了非常不同的事情

def foo(bar, *baz)
在方法调用中,如果它是最后一个参数,splat将使该参数将所有传递给函数的附加参数(有点像C#中的
params

当在方法调用(或任何其他采用参数列表的调用)中时,它会将数组变成一个裸参数列表。下面的代码段与上面的代码段等效

obj.foo(bar, biz, baz)
现在,考虑到
send
*
Symbol#to_proc
基本上是这样实现的

def foo
  yield 'called foo'
end

#usage
foo {|msg| puts msg} #idiomatic for one liners

foo do |msg| #idiomatic for multiline blocks
  puts msg
end
def foo(&block)
  return block
end

b = foo {puts 'hi'}
b.call # hi
class Symbol
  def to_proc
    Proc.new { |obj, *args| obj.send(self, *args) }
  end
end
因此,
&:sym
将创建一个新的进程,在传递给它的第一个参数上调用
.send:sym
。如果传递了任何附加的arg,它们将被全局化到一个名为
args
的数组中,然后飞溅到
send
方法调用中

我注意到&用在三个词中 位置:def foo(&block),list.map &:bar,l=lambda和方法(:put)。 它们有相同的含义吗?- 沈布莱恩

是的,有。一个&will调用
来处理它旁边的任何内容。在方法定义的情况下,当使用最后一个参数时,它有一个特殊的含义,在这个参数中,您将引入定义为块的co例程,并将其转换为proc。方法定义实际上是语言中最复杂的部分之一,数量巨大
->(x, y) { x + y }
lambda {|x, y| x + y } # same thing
l.()  # Ruby
l()  // C#
def foo(&bar)
end
baz(&quux)
class Symbol
  def to_proc
    ->(recv, *args) { recv.send self, *args }
  end
end

%w[Hello StackOverflow].map(&:length) # => [5, 13]
class Class
  def to_proc
    -> *args { new *args }
  end
end

[1, 2, 3].map(&Array) # => [[nil], [nil, nil], [nil, nil, nil]]
m = 'Hello'.method(:length)
m.() #=> 5
m = 'Hello'.:length
m.() #=> 5
[1, 2, 3].each(&method(:puts))
# 1
# 2
# 3
u = String.instance_method(:length)

u.()
# NoMethodError: undefined method `call' for #<UnboundMethod: String#length>

u.bind(42)
# TypeError: bind argument must be an instance of String

u.bind('Hello').() # => 5