【问题标题】:Ruby: how to check how many parameters a block accepts?Ruby:如何检查一个块接受多少个参数?
【发布时间】:2013-11-19 08:42:30
【问题描述】:

我正在尝试设置一个将块作为参数的方法。我知道你通过给最后一个参数一个 & 前缀来做到这一点,但是一旦它被传递,我应该如何验证它?

如果我想验证一个参数是一个字符串,我可以使用is_a?(String),例如。但是如何验证我是否收到了一个接受一个参数的块?还是 2 个?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    您可以使用Proc#arity 方法检查该块接受多少个参数:

    def foo(&block)
      puts block.arity
    end
    
    foo { }        # => 0
    foo { |a| }    # => 1
    foo { |a, b| } # => 2
    

    来自文档:

    返回不会被忽略的参数数量。如果 块被声明为不带参数,返回 0。如果块是 已知恰好取 n 个参数,返回 n。如果块有 可选参数,返回 -n-1,其中 n 是强制的数量 论据。没有参数声明的 proc 与块相同 声明 ||作为它的论据。

    【讨论】:

      【解决方案2】:

      块不是对象,所以你不能对它们做任何有用的事情(当然,yield 除外)。

      我的意思是,没有办法引用它们,它们甚至没有绑定一个名字:

      def foo
        yield 'foo'
      end
      
      foo do |bar| puts bar end
      # foo
      

      foo内部,块没有绑定任何变量,你甚至不能引用它,所以你显然也不能查询它的参数。

      可以但是要求 Ruby 将块转换为 Proc 并将其绑定到参数。然后,您可以按名称引用它,并且您可以使用完整的 Proc API,包括 Proc#parameters

      def foo(&blk)
        blk.parameters
      end
      
      foo do |m1, m2, o1=:o1, o2=:o2, *splat, m3, m4, 
            ok1: :ok1, mk1:, mk2:, ok2: :ok2, **ksplat, &blk| end
      # => [[:opt, :m1],
      #     [:opt, :m2],
      #     [:opt, :o1],
      #     [:opt, :o2],
      #     [:rest, :splat],
      #     [:opt, :m3],
      #     [:opt, :m4],
      #     [:keyreq, :mk1],
      #     [:keyreq, :mk2],
      #     [:key, :ok1],
      #     [:key, :ok2],
      #     [:keyrest, :ksplat],
      #     [:block, :blk]]
      

      但是,请注意,“块的数量”的概念在 Ruby 中是一个复杂的概念,因为块的参数绑定语义松散。块的参数绑定语义不同于方法的参数绑定语义,特别是在涉及到arity时:

      • 如果块只接受一个参数,但传递了多个参数,这不是错误,而是将参数作为绑定到参数的单个 Array 传递(就像参数已声明为 @987654329 @参数)。
      • 如果块接受多个参数,但只传递了一个参数,则该参数将转换为 Array,并将其各个元素作为参数传递(就像它们已作为 *splat 参数传递一样) .
      • 如果传递的参数多于块接受的参数,则忽略多余的参数。
      • 如果传递的参数少于块接受的参数,则额外的参数将绑定到 nil

      总而言之,语义比方法调用更接近赋值。

      例如,您会注意到,即使 m1m2 在块中被声明为强制位置参数,Proc#parameters 将它们的类型列为 :opt,即可选参数。

      换句话说:即使一个只声明一个参数的块仍然需要两个参数,而一个声明两个参数的块也可以只用一个参数调用。

      一个有用的例子:整个Enumerable mixin 是基于yield 一个单个元素的方法。但是,对于Hash,您真的想要处理两个参数key, value。你可以,因为Hash#eachyield是两个元素的Array,并且声明两个参数但只接收一个参数的块将在其参数中“splat”该参数,所以您最终会得到绑定到 key 的键和绑定到 value 的值,而无需复制和粘贴所有 Enumerables 方法的两个参数版本。

      【讨论】:

      • 注:可选参数后面的强制参数是1.9新的,关键字参数是2.0新的,强制关键字参数是2.1新的。否则你会得到一个SyntaxError。我只是想展示Proc#parameters 的全部功能(以及在关键字参数存在的情况下Proc#arity 越来越无用。)
      猜你喜欢
      • 2013-04-19
      • 2023-01-12
      • 2012-07-30
      • 2012-12-03
      • 1970-01-01
      • 2016-04-17
      • 1970-01-01
      • 2015-01-18
      相关资源
      最近更新 更多