天道酬勤,学无止境

Ruby 的代码块是否与 C# 的 lambda 表达式相同?(Is Ruby's code block same as C#'s lambda expression?)

问题

这两者本质上是一回事吗? 他们看起来和我非常相似。

lambda 表达式是否从 Ruby 借用了它的想法?

回答1

Ruby 实际上有 4 个非常相似的结构

街区

块背后的想法是一种实现真正轻量级策略模式的方法。 一个块将在函数上定义一个协程,函数可以使用 yield 关键字将控制委托给它。 我们用块只是一切的宝石,其中包括几乎所有的循环结构或任何你会使用using在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

进程

proc 基本上是获取一个块并将其作为参数传递。 一个非常有趣的用法是你可以传递一个 proc 来代替另一种方法中的块。 Ruby 有一个特殊的 proc 强制转换字符是 &,还有一个特殊规则,如果方法签名中的最后一个参数以 & 开头,它将是方法调用块的 proc 表示。 最后,有一个名为block_given?的内置方法block_given? ,如果当前方法定义了块,则返回 true。 看起来像这样

def foo(&block)
  return block
end

b = foo {puts 'hi'}
b.call # hi

更深入一点,有一个非常巧妙的技巧,将 rails 添加到 Symbol 中(并在 1.9 中合并到核心 ruby​​ 中)。 基本上, that & coercion 通过在它旁边的任何东西上调用to_proc来发挥它的魔力。 因此,rails 开发人员添加了一个 Symbol#to_proc,它会在传入的任何内容上调用自身。这使您可以为任何聚合样式函数编写一些非常简洁的代码,这些函数只是在列表中的每个对象上调用一个方法

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

更高级的东西,但真的说明了你可以用 procs 做的那种魔法

拉姆达

lambda 的用途在 ruby​​ 中与在 c# 中几乎相同,这是一种创建内联函数以传递或在内部使用的方法。 与块和过程一样,lambda 是闭包,但与前两个不同,它强制执行元数,并且从 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


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

编辑:解决评论中的问题

list.map &:bar 我可以将此语法用于接受多个参数的代码块吗? 假设我有 hash = { 0 => "hello", 1 => "world" },我想选择以 0 作为键的元素。 也许不是一个很好的例子。 – 布莱恩沉

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

基本上,ruby 没有调用方法的概念,发生的事情是对象相互传递消息。 您使用的obj.method arg语法实际上只是更明确形式的糖,即obj.send :method, arg ,并且在功能上等同于第一种语法。 这是语言中的一个基本概念,这就是method_missingrespond_to? 有道理,在第一种情况下,您只是在处理无法识别的消息,第二种情况是检查它是否正在侦听该消息。

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

def foo(bar, *baz)

在方法调用中,如果它是最后一个参数,则 splat 将使该参数将所有传递给函数的附加参数组合起来(有点像 C# 中的params

obj.foo(bar, *[biz, baz])

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

obj.foo(bar, biz, baz)

现在,考虑到send*Symbol#to_proc基本上是这样实现的

class Symbol
  def to_proc
    Proc.new { |obj, *args| obj.send(self, *args) }
  end
end

所以, &:sym将创建一个新的过程,它在传递给它的第一个参数上调用.send :sym 。 如果传递了任何额外的 args,它们将被整合到一个名为args的数组中,然后被放入send方法调用中。

我注意到 & 用在三个地方:def foo(&block)、list.map &:bar 和 l = lambda &method(:puts)。 它们具有相同的含义吗? – 布莱恩沉

是的,他们这样做。 & 会在它旁边的任何东西上调用to_proc 。 在方法定义的情况下,它在最后一个参数上具有特殊含义,您将引入定义为块的协程,并将其转换为 proc。 方法定义实际上是语言中最复杂的部分之一,参数中有大量的技巧和特殊含义,以及参数的放置。

b = {0 => "df", 1 => "kl"} p b.select {|key, value| 关键.零? 我试图将其转换为 p b.select &:zero?,但它失败了。 我猜这是因为代码块的参数数量是两个,但是 &:zero? 只能带一个参数。 有什么办法可以做到吗? – 布莱恩沉

这应该早点解决,不幸的是你不能用这个技巧来做到这一点。

“方法是一种将现有函数变成可以放入变量的东西的方法。” 为什么 l = method(:puts) 不够用? lambda & 在这种情况下是什么意思? – 布莱恩沉

这个例子非常人为,我只是想展示与它之前的例子等效的代码,在那里我将一个 proc 传递给lambda方法。 稍后我会花一些时间重新编写该部分,但是您是对的, method(:puts)完全足够。 我想说明的是,你可以在任何需要阻塞的地方使用&method(:puts) 。 一个更好的例子是这个

['hello', 'world'].each &method(:puts) # => hello\nworld

l = -> {|味精| puts msg} #ruby 1.9:这对我不起作用。 在我检查了 Jörg 的答案后,我认为它应该是 l = -> (msg) {puts msg}。 或者我使用了不正确的 Ruby 版本? 我的是 ruby​​ 1.9.1p738 – Bryan Shen

就像我在帖子中所说的那样,我在写答案时没有可用的 irb,你是对的,我弄错了(我大部分时间都在 1.8.7 中度过,所以我不习惯新语法)

刺位和括号之间没有空格。 尝试l = ->(msg) {puts msg} 。 这种语法实际上有很多阻力,因为它与语言中的其他一切都大不相同。

回答2

C# 与 Ruby

这两者本质上是一回事吗? 他们看起来和我非常相似。

它们非常不同。

首先,C# 中的 lambdas 做两件非常不同的事情,其中​​只有一个在 Ruby 中具有等价物。 (等价的是,惊喜,lambdas,而不是块。)

在 C# 中,lambda 表达式文字被重载。 (有趣的是,据我所知,它们是唯一重载的文字。)而且它们的结果类型是重载的。 (同样,它们在C#唯一可在其结果类型被重载,方法只能在他们的参数类型被重载。)

C#lambda表达式文字可以匿名一段可执行代码匿名一段可执行代码的抽象表示,这取决于它们的结果类型是否是Func / ActionExpression

Ruby 没有后一种功能的任何等价物(嗯,有特定于解释器的不可移植的非标准化扩展)。 前一个功能的等价物是一个 lambda,而不是一个块。

lambda 的 Ruby 语法与 C# 非常相似:

->(x, y) { x + y }           # Ruby
(x, y) => { return x + y; } // C#

在 C# 中,如果只有一个表达式作为主体,则可以删除return 、分号和花括号:

->(x, y) { x + y }  # Ruby
(x, y) => x + y    // C#

如果您只有一个参数,则可以省略括号:

-> x { x }  # Ruby
x => x     // C#

在 Ruby 中,如果参数列表为空,您可以不使用它:

-> { 42 }  # Ruby
() => 42  // C#

在 Ruby 中使用文字 lambda 语法的另一种方法是将块参数传递给Kernel#lambda方法:

->(x, y) { x + y }
lambda {|x, y| x + y } # same thing

这两者之间的主要区别在于您不知道lambda作用,因为它可以被覆盖、覆盖、包装或以其他方式修改,而文字的行为不能在 Ruby 中修改。

在 Ruby 1.8 中,您也可以使用Kernel#proc尽管您可能应该避免使用它,因为该方法在 1.9 中做了一些不同的事情。

Ruby 和 C# 之间的另一个区别是调用lambda 的语法:

l.()  # Ruby
l()  // C#

即,在 C# 中,调用 lambda 的语法与调用其他任何东西时使用的语法相同,而在 Ruby 中,调用方法的语法与调用任何其他类型的可调用对象的语法不同。

另一个区别是,在 C# 中, ()内置于语言中,仅适用于某些内置类型,如方法、委托、 ActionFunc ,而在 Ruby 中, .()只是.call()和因此,只需实现一个call方法就可以与任何对象一起工作。

procs 与 lambdas

那么,究竟什么lambda? 好吧,它们是Proc类的实例。 除了有一点点复杂之外:实际上有两种不同类型的Proc类实例,它们略有不同。 (恕我直言, Proc类应该分为两种不同类型的对象的两个类。)

特别是,并非所有Proc都是 lambda。 您可以通过调用Proc#lambda?来检查Proc是否为Proc#lambda? 方法。 (通常的约定是将 lambda Proc称为“lambdas”,将非 lambda Proc称为“procs”。)

非 lambda 过程是通过将块传递给Proc.newKernel#proc 。 但是,请注意,在 Ruby 1.9 之前, Kernel#proc创建一个lambda ,而不是一个 proc。

有什么不同? 基本上,lambdas 的行为更像方法,procs 的行为更像块。

如果您关注了 Project Lambda for Java 8 邮件列表中的一些讨论,您可能会遇到一个问题,即完全不清楚非本地控制流应该如何与 lambdas 一起工作。 特别是,在 lambda 中有三种可能的return行为(好吧,三种可能,但只有两种是真正明智的):

  • 从 lambda 返回
  • 从调用 lambda 的方法返回
  • 从创建 lambda 的方法返回

最后一个有点不确定,因为通常该方法已经返回,但其他两个都非常有意义,并且没有一个比另一个更正确或更明显。 Java 8 的 Lambda 项目的当前状态是它们使用两个不同的关键字( returnyield )。 Ruby 使用两种不同类型的Proc

  • procs 从调用方法返回(就像块一样)
  • lambdas 从 lambda 返回(就像方法一样)

它们在处理参数绑定的方式上也有所不同。 同样,lambda 的行为更像方法,而 proc 的行为更像块:

  • 您可以将比参数更多的参数传递给 proc,在这种情况下,多余的参数将被忽略
  • 您可以向 proc 传递比参数少的参数,在这种情况下,多余的参数将被绑定到nil
  • 如果传递的单个参数,它是一个Array (或响应于to_ary )和proc有多个参数,该阵列会解压缩并结合到参数中的元素(完全一样,他们会在解构分配的情况下)

块:轻量级过程

一个块本质上是一个轻量级的过程。 Ruby 中的每个方法都有一个块参数,它实际上没有出现在它的参数列表中(稍后会详细介绍),即是隐式的。 这意味着在每个方法调用中,您都可以传递一个块参数,无论该方法是否需要它。

由于块没有出现在参数列表中,因此没有可以用来引用它的名称。 那么,你如何使用它? 好吧,您唯一可以做的两件事(不是真的,但稍后会详细介绍)是通过yield关键字隐式调用它并检查块是否通过block_given?传递block_given? . (因为没有名字,你不能使用callnil?方法。你会用什么来称呼它们?)

大多数 Ruby 实现都以非常轻量级的方式实现块。 特别是,它们实际上并没有将它们实现为对象。 但是,由于它们没有名称,因此您无法引用它们,因此实际上无法判断它们是否对象。 您可以将它们视为 proc,这会更容易,因为要记住的概念不同。 只需将它们实际上并未作为块实现为编译器优化这一事实。

to_proc&

其实一种方法来指代一个块:在&印记/修改/一元前缀运算符。 它只能出现在参数列表和参数列表中。

参数列表中,它的意思是“隐式块包装到一个过程中并将其绑定到这个名称”。 在参数列表中,它的意思是“将这个Proc解包成一个块”。

def foo(&bar)
end

在方法内部, bar现在绑定到代表块的 proc 对象。 例如,这意味着您可以将其存储在实例变量中以备后用。

baz(&quux)

在这种情况下, baz实际上是一个采用零参数的方法。 但当然,它采用了所有 Ruby 方法都采用的隐式块参数。 我们正在传递变量quux的内容,但首先将其展开到一个块中。

这种“展开”实际上不仅适用于Proc&首先在对象上调用to_proc ,将其转换为 proc。 这样,任何对象都可以转换为块。

最广泛使用的例子是Symbol#to_proc ,我相信它最早出现在 90 年代后期的某个时候。 当它被添加到 ActiveSupport 时,它变得流行起来,并从那里传播到 Facets 和其他扩展库。 最后,它被添加到 Ruby 1.9 核心库中,并向后移植到 1.8.7。 这很简单:

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]]

Method s 和UnboundMethod s

另一个代表一段可执行代码的类是Method类。 Method对象是Method的具体化代理。 您可以通过在任何对象上调用Object#method并传递要具体化的方法的名称来创建Method对象:

m = 'Hello'.method(:length)
m.() #=> 5

或使用方法引用运算符.: :

m = 'Hello'.:length
m.() #=> 5

Method响应to_proc ,因此您可以将它们传递到任何可以传递块的地方:

[1, 2, 3].each(&method(:puts))
# 1
# 2
# 3

UnboundMethod是尚未绑定到接收器的方法的代理,即尚未定义self的方法。 您不能调用UnboundMethod ,但可以bindbind到一个对象(该对象必须是您从中获取该方法的模块的实例),这会将其转换为Method

UnboundMethod对象是通过调用Module#instance_method系列中的方法之一创建的,并将方法的名称作为参数传递。

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

通用的可调用对象

就像我上面已经暗示的那样: Proc s 和Method s 没有什么特别之处。 任何响应call对象都可以被调用,任何响应to_proc对象都可以转换为Proc ,从而解包成一个块并传递给一个需要一个块的方法。

历史

lambda 表达式是否从 Ruby 借用了它的想法?

可能不会。 大多数现代编程语言都有某种形式的匿名文字代码块:Lisp (1958)、Scheme、Smalltalk (1974)、Perl、Python、ECMAScript、Ruby、Scala、Haskell、C++、D、Objective-C,甚至 PHP(! )。 当然,整个想法可以追溯到 Alonzo Church 的 λ 演算(1935 年甚至更早)。

回答3

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

他们都借鉴了 Lisp(一种可追溯到 1950 年代后期的编程语言)的想法,而 Lisp 又从 1930 年代发明的 Church 的 Lambda 演算中借用了 lambda 概念。

标签

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 如何在 C# 方法中使用 IronRuby 块(How to use an IronRuby block with a C# method)
    问题 我正在使用 IronRuby 并试图找出如何使用带有 C# 方法的块。 这是我试图模拟的基本 Ruby 代码: def BlockTest () result = yield("hello") puts result end BlockTest { |x| x + " world" } 我尝试用 C# 和 IronRuby 做同样的事情是: string scriptText = "csharp.BlockTest { |arg| arg + 'world'}\n"; ScriptEngine scriptEngine = Ruby.CreateEngine(); ScriptScope scriptScope = scriptEngine.CreateScope(); scriptScope.SetVariable("csharp", new BlockTestClass()); scriptEngine.Execute(scriptText, scriptScope); BlockTestClass 是: public class BlockTestClass { public void BlockTest(Func<string, string> block) { Console.WriteLine(block("hello ")); } } 当我运行 C# 代码时
  • Ruby块的最佳解释? [关闭](Best explanation of Ruby blocks? [closed])
    问题 关门了。 这个问题是基于意见的。 它当前不接受答案。 想要改善这个问题吗? 更新问题,以便可以通过编辑此帖子以事实和引用的形式回答。 7年前关闭。 改善这个问题 您可以共享的Ruby块的最佳解释是什么? 用法和编写代码可能会花费很多时间? 回答1 我对此回答提供了自己的解释,并做了一些修改: Ruby中的“块”与通用编程术语“代码块”或“代码块”不同。 假装一下以下(无效的)Ruby代码实际上有效: def add10( n ) puts "#{n} + 10 = #{n+10}" end def do_something_with_digits( method ) 1.upto(9) do |i| method(i) end end do_something_with_digits( add10 ) #=> "1 + 10 = 11" #=> "2 + 10 = 12" ... #=> "9 + 10 = 19" 尽管该代码无效,但它的意图(将某些代码传递给某个方法并让该方法运行该代码)可以在Ruby中以多种方式实现。 这些方法之一是“块”。 Ruby中的Block非常非常类似于一种方法:它可以接受一些参数并为其运行代码。 每当您看到foo{ |x,y,z| ... } foo{ |x,y,z| ... }或foo do |x,y,z| ... end foo do |x
  • Ruby有Python没有的,反之亦然?(What does Ruby have that Python doesn't, and vice versa?)
    问题 已锁定。 该问题及其答案被锁定,因为该问题是题外话,但具有历史意义。 它目前不接受新的答案或互动。 关于Python和Ruby的讨论很多,我都发现它们完全无济于事,因为它们都绕开了为什么功能X吸收了语言Y的理由,或者声称语言Y没有X,尽管实际上确实如此。 我也确切地知道为什么我偏爱Python,但这也是主观的,并且不会帮助任何人选择,因为他们在开发中可能没有和我一样的爱好。 因此,客观列出差异会很有趣。 因此,没有“ Python的lambdas很烂”。 相反,请解释Ruby的lambda可以做什么,而Python则不能。 没有主观性。 示例代码很好! 请在一个答案中没有几个差异。 然后,将您所知道的正确或不正确(或主观的)否决。 同样,语法上的差异也不是很有趣。 我们知道Python用缩进来做,而Ruby用括号和尾来做,@在Python中被称为self。 更新:这现在是社区Wiki,因此我们可以在此处添加较大的差异。 Ruby在类主体中有一个类引用 在Ruby中,您已经在类主体中引用了该类(自身)。 在Python中,直到类构造完成后,您才可以引用该类。 一个例子: class Kaka puts self end 在这种情况下,self是类,并且此代码将打印出“ Kaka”。 无法打印出类名,也无法以其他方式从Python中的类定义主体(外部方法定义)访问该类。
  • ruby 块并从块中返回一些东西(ruby block and returning something from block)
    问题 我正在使用 ruby​​ 1.8.7。 p = lambda { return 10;} def lab(block) puts 'before' puts block.call puts 'after' end lab p 上面的代码输出是 before 10 after 我将相同的代码重构为这个 def lab(&block) puts 'before' puts block.call puts 'after' end lab { return 10; } 现在我收到 LocalJumpError:意外返回。 对我来说,这两个代码都在做同样的事情。 是的,在第一种情况下我传递了一个过程,在第二种情况下我传递了一个块。 但是 &block 将该块转换为 proc。 所以 proc.call 应该表现相同。 是的,我看过这篇文章 Using 'return' in a Ruby block 回答1 当您使用 & 传入块时,您将其转换为 proc。 重要的一点是proc 和 lambda 是不同的(lambda 实际上是 proc 的子类),特别是它们如何处理 return。 所以你重构的代码实际上相当于: p = Proc.new { return 10;} def lab(block) puts 'before' puts block.call puts 'after'
  • Ruby中的proc和lambda有什么区别?(What's the difference between a proc and a lambda in Ruby?)
    问题 您什么时候会使用一个而不是另一个? 回答1 一种区别是它们处理参数的方式。 使用proc {}和Proc.new {}创建proc是等效的。 但是,使用lambda {}为您提供了一个过程,可以检查传递给它的参数数量。 来自ri Kernel#lambda : 与Proc.new等效,除了生成的Proc对象检查调用时传递的参数数量。 一个例子: p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28@(irb):1> p.call 1, 2 # => 5 p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass p.call 1, 2, 3 # => 5 l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c@(irb):5 (lambda)> l.call 1, 2 # => 5 l.call 1 # => ArgumentError: wrong number of arguments (1 for 2) l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2) 此外,正如Ken所指出的那样
  • 你如何在 lambda 演算术语中定义匿名函数(或者我怎么能说某些语言支持匿名函数)?(How do you define an anonymous function in lambda calculus terms (or how can I say some language supports anonymous functions)?)
    问题 java 是否支持当前版本的 6 个 lambda 表达式或“匿名函数”? 有什么我不能在 Java 中做而我不能用支持 lambda 表达式的编程语言做的吗? 我知道java是图灵完备的,所以你可以在其中做“任何事情”。 为什么匿名内部类包装函数不能表示 lambda 演算中定义的函数? 匿名函数究竟是什么,你怎么能说某些语言支持匿名函数? 回答1 正如我在上面的评论中已经暗示的那样,问题实际上取决于您如何准确定义“支持”。 在您的问题中,您已经提到 Java 是图灵完备的,因此 Java“支持”(对于“支持”的某些定义)所有其他编程语言都支持的所有内容。 Java确实支持匿名函数:只需在 Java 中为 λ 演算编写一个解释器,并将匿名函数作为字符串传入。 但是,我发现使用匿名函数工作量太大。 所以,对我来说,有趣的问题不是 Java 是否支持匿名函数,而是当我想使用匿名函数时,Java 是否支持我。 IOW:Java 是否使匿名函数的使用变得容易,它是否指导我,对我有帮助? 让我们做一个简单的实验:实现map函数并使用它来将列表[1, 2, 3, 4, 5]的每个元素增加1 。 哈斯克尔 以下是morph的实现(我将调用该函数以免与现有的内置map函数发生冲突)在 Haskell 中的实现方式如下: morph _ [] = [] morph f (x:xs) = f
  • 什么是 lambda,什么是示例实现?(What is a lambda and what is an example implementation?)
    问题 我对编程相当陌生,虽然阅读了大量的 lambda 概念,但这个概念不断出现,但我很难弄清楚它究竟是什么以及如何实现它会让我的编程生活变得更好。 首先,什么是 lambda,其次是如何实现的? 感谢所有发帖的人。 正如评论中所提到的,这是一个重复的,但是这里有很多很棒的答案,我想为社区保留它们,所以我将它变成了社区帖子。 这是另一个问题的链接: 什么是 lambda(函数)? 回答1 Lambda 很难捕捉,但是一旦你想象了它们,你就无法理解为什么之前没有得到它。 Lamdba 是匿名函数 Lambda 是普通函数,唯一的区别是你不给它们命名。 要理解这一点,您首先必须知道,当您创建一个函数时,代码存储在内存中只有计算机知道的地址。 所以当你做这样的事情时: function Foo () { /* your code here */ } 您真正要做的是将名称“Foo”绑定到内存中代码的地址。 现在,还有另一种访问地址的方法:引用(和指针,但让我们跳过这个讨厌的家伙) 好吧,一个 lambda 函数是一个没有名字的函数,所以它只能通过它的引用来访问。 你如何使用它们? 创建 lambda 函数时,您通常只打算使用它一次。 分步过程通常是: 创建函数获取参考将引用传递到将要使用的地方 最后,引用丢失,函数自动销毁。 典型的用例是回调函数。 您在一行中声明、创建和传递函数
  • map(&:name) 在 Ruby 中是什么意思?(What does map(&:name) mean in Ruby?)
    问题 我在 RailsCast 中找到了这段代码: def tag_names @tag_names || tags.map(&:name).join(' ') end 什么是(&:name)在map(&:name)是什么意思? 回答1 它是tags.map(&:name.to_proc).join(' ')的简写 如果foo是具有to_proc方法的对象,那么您可以将其作为&foo传递给方法,该方法将调用foo.to_proc并将其用作方法的块。 Symbol#to_proc方法最初由 ActiveSupport 添加,但已集成到 Ruby 1.8.7 中。 这是它的实现: class Symbol def to_proc Proc.new do |obj, *args| obj.send self, *args end end end 回答2 另一个很酷的速记,很多人都不知道,是 array.each(&method(:foo)) 这是一个简写 array.each { |element| foo(element) } 通过调用method(:foo)我们从self中获取了一个Method对象来表示它的foo方法,并使用&来表示它有一个to_proc方法可以将它转换成一个Proc 。 当你想做无点风格的事情时,这非常有用。 一个例子是检查数组中是否有任何字符串等于字符串"foo
  • map(&:name)在Ruby中是什么意思?(What does map(&:name) mean in Ruby?)
    问题 我在RailsCast中找到了以下代码: def tag_names @tag_names || tags.map(&:name).join(' ') end 什么是(&:name)在map(&:name)是什么意思? 回答1 这是tags.map(&:name.to_proc).join(' ')的简写 如果foo是具有to_proc方法的对象,则可以将其作为&foo传递给方法,该方法将调用foo.to_proc并将其用作方法的块。 Symbol#to_proc方法最初是由ActiveSupport添加的,但已集成到Ruby 1.8.7中。 这是它的实现: class Symbol def to_proc Proc.new do |obj, *args| obj.send self, *args end end end 回答2 许多人不知道的另一个很酷的速记是 array.each(&method(:foo)) 这是的简写 array.each { |element| foo(element) } 通过调用method(:foo)我们从self那里获取了一个Method对象,该对象代表其foo方法,并使用&表示它具有to_proc方法,可将其转换为Proc 。 当您想做无指向性的样式时,这非常有用。 一个示例是检查数组中是否有任何与字符串"foo"相等的字符串。 有常规方法
  • C#:相当于 python try/catch/else 块(C#: Equivalent of the python try/catch/else block)
    问题 在 Python 中,有这个有用的异常处理代码: try: # Code that could raise an exception except Exception: # Exception handling else: # Code to execute if the try block DID NOT fail 我认为能够将可能引发和异常的代码与正常代码分开是很有用的。 在 Python 中,这是可能的,如上所示,但是我在 C# 中找不到类似的东西。 假设该功能或类似功能不存在,将普通代码放在try块中或catch块之后是标准做法吗? 我问的原因是因为我有以下代码: if (!IsReadOnly) { T newobj; try { newobj = DataPortal.Update<T>(this); List<string> keys = new List<string>(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } } catch (DataPortalException) { // TODO: Implement DataPortal.Update<T>() recovery
  • Ruby中的闭包和for循环(Closures and for loops in Ruby)
    问题 我是Ruby的新手,有些闭包逻辑让我感到困惑。 考虑以下代码: array = [] for i in (1..5) array << lambda {i} end array.map{|f| f.call} # => [5, 5, 5, 5, 5] 这对我来说很有意义,因为我被约束在循环之外,因此每次循环都捕获相同的变量。 对我来说,使用each块可以解决此问题也很有意义: array = [] (1..5).each{|i| array << lambda {i}} array.map{|f| f.call} # => [1, 2, 3, 4, 5] ...因为我现在每次都要分别声明。 但是现在我迷路了:为什么我也不能通过引入中间变量来解决它? array = [] for i in 1..5 j = i array << lambda {j} end array.map{|f| f.call} # => [5, 5, 5, 5, 5] 因为j在循环中每次都是新的,所以我认为每次通过都会捕获一个不同的变量。 例如,这绝对是C#的工作方式,而且-我认为-Lisp的举止行为。 但是在Ruby中并没有那么多。 到底发生了什么事? 编辑:查看答案中的注释; 问题似乎是j仍然在循环之外。 范围作用域如何真正起作用? 编辑:我想我还是不明白; 如果循环不创建新的作用域,为什么这样做:
  • C#:匿名方法与命名方法(C#: Anonymous method vs Named method)
    问题 我是SO和编程和学习的新手,每天都有零碎的技术(C#)行话。 谷歌搜索一段时间后,下面是我对methods研究 方法是一个语句块,用于代码的可重用性,它还支持使用不同的SIGNATURE进行重载。例如:drawShape(2pts),drawShape(3pts)等... Anonymous方法是一种带有语句块的方法,但没有名称。...(出于不成熟的要求,在wt情况下,我们会遇到匿名方法...任何文章,示例...) Named method :这是一个链接,但最后我没有得到命名方法实际上是什么... 谁能解释什么是“命名”方法,以及我们在哪里使用匿名方法? 回答1 命名方法是可以通过其名称调用的方法(例如,它是具有名称的函数)。 例如,您定义了一个将两个数字相加的函数: int f(int x, int y) { return x+y; } 您可以通过如下名称来调用此方法: f(1, 2); 。 匿名方法是一种无需参数名称即可作为参数传递给函数的方法。 这些方法可以在运行时构造,也可以在编译时从lambda表达式求值。 这些方法通常在LINQ查询中使用,例如: int maxSmallerThan10 = array.Where(x => x < 10).Max(); 表达式x => x < 10称为lambda表达式,其结果是一个匿名函数,将由Where方法运行。
  • 表达式树练习实践:C# 五类运算符的表达式树表达
    表达式树练习实践:C# 运算符目录表达式树练习实践:C# 运算符&、|、^、~、<&&、||、!==、!=、>、+ 与 Add()- 与 Subtract()乘除、取模自增自减一,算术运算符二,关系运算符三,逻辑运算符四,位运算符五,赋值运算符六,其他运算符在 C# 中,算术运算符,有以下类型算术运算符关系运算符逻辑运算符位运算符赋值运算符其他运算符这些运算符根据参数的多少,可以分作一元运算符、二元运算符、三元运算符。本文将围绕这些运算符,演示如何使用表达式树进行操作。对于一元运算符和二元运算符的 Expression 的子类型如下:UnaryExpression; //一元运算表达式 BinaryExpression; //二元运算表达式一,算术运算符运算符描述+把两个操作数相加-从第一个操作数中减去第二个操作数*把两个操作数相乘/分子除以分母%取模运算符,整除后的余数++自增运算符,整数值增加 1--自减运算符,整数值减少 1+ 与 Add()正常代码 int a; int b; a = 100; b = 200; var ab = a + b; Console.WriteLine(ab);使用表达式树构建 ParameterExpression a = Expression.Parameter(typeof(int), "a"); ParameterExpression b
  • Ruby中的“ for”与“ each”(“for” vs “each” in Ruby)
    问题 我只是对Ruby中的循环有一个简单的问题。 这两种遍历集合的方式之间有区别吗? # way 1 @collection.each do |item| # do whatever end # way 2 for item in @collection # do whatever end 只是想知道它们是否完全相同,或者是否存在细微差别(可能是@collection为nil时)。 回答1 这是唯一的区别: 每个: irb> [1,2,3].each { |x| } => [1, 2, 3] irb> x NameError: undefined local variable or method `x' for main:Object from (irb):2 from :0 为了: irb> for x in [1,2,3]; end => [1, 2, 3] irb> x => 3 使用for循环,迭代器变量在该块完成后仍然存在。 对于each循环,它不会,除非在循环开始之前已将其定义为局部变量。 除此之外, for只是each方法的语法糖。 当@collection为nil两个循环都会引发异常: 例外:main:Object的未定义局部变量或方法“ @collection” 回答2 有关详细说明,请参见“ For循环的弊端”(考虑变量作用域有一个小差异)。
  • 为什么在 c# 中 if 和委托的范围是这种方式(Why is the scope of if and delegates this way in c#)
    问题 受到这个问题的启发,我开始想知道为什么以下示例在 c# 中都是非法的: VoidFunction t = delegate { int i = 0; }; int i = 1; 和 { int i = 0; } int i = 1; 我只是想知道是否有人知道这种语言被设计成这种方式的确切原因? 是为了阻止不良的编程实践,如果是这样,为什么不只是发出警告?出于性能原因(编译和运行时)或原因是什么? 回答1 C# 语言规范的第 3 节中介绍了此行为。 这是规范中的引用 类似地,任何以 lambda 表达式形式作为匿名函数体出现的表达式都会创建一个包含匿名函数参数的声明空间。 局部变量声明空间的两个成员具有相同名称是错误的。 块的局部变量声明空间和嵌套的局部变量声明空间包含同名元素是错误的。 因此,在嵌套声明空间内,不可能声明与封闭声明空间中的局部变量或常量同名的局部变量或常量。 我认为更简单的阅读方式是,为了变量声明(以及许多其他与块相关的函数),lambda/匿名委托块与普通块没有区别。 至于为什么语言是这样设计的,规范没有明确说明。 我的观点是简单。 如果将代码视为只是另一个块,那么它会使代码分析例程更容易。 您可以保留所有现有例程来分析块的语义错误和名称解析。 当您考虑可变提升时,这一点尤其重要。 Lambda 最终将是一个不同的函数
  • 我应该具备哪些 Ruby 知识? [关闭](what Ruby knowledge should I have? [closed])
    问题 就目前而言,这个问题不适合我们的问答形式。 我们希望答案得到事实、参考或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。 如果您觉得此问题可以改进并可能重新打开,请访问帮助中心以获取指导。 7年前关闭。 我刚刚发现我应该拥有哪些 C# 知识? 问题并想知道同样的问题,但对于 Ruby。 我认为 Ruby 是我最喜欢的编程语言,除了学习基础知识,至少我从许多 Ruby on Rails 项目和一些 Ruby 脚本中学到的东西,我还尝试通过阅读 Gluttonous、O' 等博客来学习Reilly Ruby、Ola Bini 和抛光 Ruby。 我也读过像 The Ruby Way 这样的书。 但是,在接受有关我的 Ruby 技能的面试时,我还没有做好充分的准备。 有人问我是否知道闭包,起初我回答说我不知道​​,但后来我问面试官是否指的是代码块,比如 lambda 和do ... end ,他知道了。 我是如何进行 3 年的 Ruby 编程并试图在不学习闭包 = 代码块的情况下学习这门语言的? 所以,我要问你的问题是 Ruby 程序员应该具备哪些 Ruby 语言知识? 作为 Ruby 职位的面试官,您希望我知道什么? 只需列出一些主题,我就会阅读有关它们的内容。 如果您认为有必要,列出 Ruby 特定的工具(如 Ruby on Rails、Rake、Rack 等
  • Objective-C的Block,递归与泛型
    Objective-C的Block Apple在C,Objective-C和C++中扩充了Block这种文法的,并且在GCC4.2中进行了支持。现在我们可以在Mac 10.6和iOS 4中使用。如果是Mac 10.6 或 iOS 4.0 之前的平台,据说可以用http://code.google.com/p/plblocks/这个项目来支持Block语法。 Apple在 Snow Leopard中所用到的Grand Central Dispatch(GCD)就是基于Blocks实现的。Grand Central Dispatch是苹果开发的工具,目的是帮助开发者更容易的利用多核处理器的并行处理功能。关于Blocks以及GCD在苹果官方的介绍,请见:Introducing Blocks and Grand Central Dispatch。 你可以把它理解为函数指针,匿名函数,闭包,lambda表达式,这里暂且用块对象来表述,因为它们之间还是有些许不同的。 块对象 块对象是C级别的文法,同时也是一种运行时特征,即它允许您把函数表达式组合在一起,组合结果可作为参数传递也可保存,还可供多个线程使用。块对象的函数表达式可引用或持有局部变量。在其他的语言环境中,块对象有时也被称为closure或者lambda。如果您需创建可如数值般传递的工作单元(即代码段),则可使用块对象
  • 何时使用lambda,何时使用Proc.new?(When to use lambda, when to use Proc.new?)
    问题 在Ruby 1.8中,一方面proc / lambda与另一方面Proc.new之间存在细微的差异。 这些区别是什么? 您能提供有关如何决定选择哪一个的指导吗? 在Ruby 1.9中,proc和lambda是不同的。 这是怎么回事? 回答1 使用lambda创建的Proc.new和使用Proc.new创建的Proc.new之间的另一个重要但细微的区别是它们如何处理return语句: 在由lambda创建的proc中, return语句仅从proc本身返回在Proc.new创建的proc中, return语句有点令人惊讶:它不仅从proc还从封装proc的方法中返回控制! 这是由lambda创建的proc的return 。 它的行为可能与您预期的一样: def whowouldwin mylambda = lambda {return "Freddy"} mylambda.call # mylambda gets called and returns "Freddy", and execution # continues on the next line return "Jason" end whowouldwin #=> "Jason" 现在,这是一个由Proc.new创建的proc的return执行相同的操作。 您将看到以下其中一种情况,其中Ruby打破了广受赞誉的
  • Ruby 中 &(&符号)的目的是用于过程和调用方法(Purpose of & (ampersand) in Ruby for procs and calling methods)
    问题 我注意到很多处理 Ruby Procs 的例子都有下面的 & 符号。 # Ruby Example shout = Proc.new { puts 'Yolo!' } def shout_n_times(n, &callback) n.times do callback.call end end shout_n_times(3, &shout) # prints 'Yolo!' 3 times 我的问题是 & 符号背后的功能目的是什么? 似乎如果我在没有 & 的情况下编写了完全相同的代码,它会按预期工作: # Same code as previous without & shout = Proc.new { puts 'Yolo!' } def shout_n_times(n, callback) n.times do callback.call end end shout_n_times(3, shout) # prints 'Yolo!' 3 times 回答1 本文很好地概述了这些差异。 总结本文,Ruby 允许隐式和显式块。 此外,Ruby 有 block、proc 和 lambda。 你打电话的时候 def foo(block) end block只是方法的一个简单参数。 参数在变量block被引用,你如何与它交互取决于你传递的对象类型。 def foo(one
  • “闭包”和“块”到底有什么区别?(Exactly what is the difference between a “closure” and a “block”?)
    问题 我发现很多人交替使用闭包和块这两个词。 大多数人无法解释他们在说什么。 一些 Java 程序员(甚至那些来自非常昂贵的咨询公司的程序员)将匿名内部类称为“块”和“闭包”——但我知道这不是真的。 (您不能从定义它们的方法的范围内传递可变变量......) 我在找: 一个块的精确的计算机科学定义闭包的精确的计算机科学定义并澄清两者之间的区别。 我真的很想看到关于这些的链接、文章或书籍参考。 回答1 虽然块只是一段可以由语句和声明组成的代码,但没有别的,闭包是一个真正的第一类对象,一个真正的变量,它的值是一个块。 主要区别在于块只是将指令组合在一起(例如while语句的主体),而闭包是一个变量,其中包含一些可以执行的代码。 如果你有一个闭包,通常你可以将它作为参数传递给函数,对其进行柯化和去柯化,主要是调用它! Closure c = { println 'Hello!' } /* now you have an object that contains code */ c.call() 当然,闭包更强大,它们是变量,可用于定义对象的自定义行为(而通常您必须在编程中使用接口或其他 OOP 方法)。 您可以将闭包视为一个函数,其中包含该函数在其自身内部所做的事情。 块很有用,因为它们允许确定变量的范围。 通常,当您在作用域内定义变量时,您可以毫无问题地覆盖外部定义