代码之家  ›  专栏  ›  技术社区  ›  Amin Shah Gilani

double splat在方法调用中做什么?

  •  1
  • Amin Shah Gilani  · 技术社区  · 6 年前

    在准备 Ruby Association Certified Ruby Programmer Exam ,我正在解决 prep test 在这种情况下:

    def add(x:, y:, **params)
      z = x + y
    
      params[:round] ? z.round : z
    end
    
    
    p add(x: 3, y: 4) #=> 7 // no surprise here
    p add(x: 3.75, y: 3, round: true) #=> 7 // makes total sense
    options = {:round => true}; p add(x: 3.75, y: 3, **options) #=> 7 // huh?
    

    现在,我知道如何使用double splat将参数中的参数转换为散列,例如:

    def splat_me(a, *b, **c)
      puts "a = #{a.inspect}"
      puts "b = #{b.inspect}"
      puts "c = #{c.inspect}"
    end
    
    splat_me(1, 2, 3, 4, a: 'hello', b: 'world')
    
    #=> a = 1
    #=> b = [2, 3, 4]
    #=> c = {:a=>"hello", :b=>"world"}
    

    不过,我也知道你不能随便翻倍。

    options = {:round => true}
    **options
    
    #=> SyntaxError: (irb):44: syntax error, unexpected **arg
    #=> **options
    #=>   ^
    

    :

    双喇叭有什么用( ** 电话 (不是定义)?

    options = {:round => true}; p add(x: 3.75, y: 3, **options)
    

    比这更好:

    options = {:round => true}; p add(x: 3.75, y: 3, options)
    

    测试双splat的有用性(未找到)

    不管有没有参数都是一样的。

    def splat_it(**params)
      params
    end
    
    opts = {
      one: 1,
      two: 2,
      three: 3
    }
    
    a = splat_it(opts)   #=> {:one=>1, :two=>2, :three=>3}
    b = splat_it(**opts) #=> {:one=>1, :two=>2, :three=>3}
    
    a.eql? b # => true
    

    我的意思是,您甚至可以毫无问题地将散列传递给用关键字params定义的方法,它将智能地分配适当的关键字:

    def splat_it(one:, two:, three:)
      puts "one   = #{one}"
      puts "two   = #{two}"
      puts "three = #{three}"
    end
    
    opts = {
      one: 1,
      two: 2,
      three: 3
    }
    
    a = splat_it(opts)   #=> {:one=>1, :two=>2, :three=>3}
    #=> one   = 1
    #=> two   = 2
    #=> three = 3
    
    b = splat_it(**opts) #=> {:one=>1, :two=>2, :three=>3}
    #=> one   = 1
    #=> two   = 2
    #=> three = 3
    

    随机类上的双splat to_h to_hash 方法不会做没有它就做不到的事情:

    Person = Struct.new(:name, :age)
    
    Person.class_eval do
      def to_h
        {name: name, age: age}
      end
    
      alias_method :to_hash, :to_h
    end
    
    bob = Person.new('Bob', 15)
    
    p bob.to_h #=> {:name=>"Bob", :age=>15}
    
    
    def splat_it(**params)
      params
    end
    
    splat_it(**bob) # => {:name=>"Bob", :age=>15}
    splat_it(bob)   # => {:name=>"Bob", :age=>15}
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   Aleksei Matiushkin    6 年前

    可能需要对输入参数进行解构。在这种情况下,简单的散列不起作用:

    params = {foo: 42, bar: :baz}
    def t1(foo:, **params); puts params.inspect; end
    #⇒ :t1
    def t2(foo:, params); puts params.inspect; end 
    #⇒ SyntaxError: unexpected tIDENTIFIER
    def t2(params, foo:); puts params.inspect; end
    #⇒ :t2
    

    现在让我们来测试一下:

    t1 params
    #⇒ {:bar=>:baz}
    t2 params
    #⇒ ArgumentError: missing keyword: foo
    t2 **params
    #⇒ ArgumentError: missing keyword: foo
    

    也就是说,double splat允许透明的参数解构。

    如果有人好奇它为什么有用, foo 强制性的 在此语法中调用方法的参数。


    中的非格参数 调用函数

    h1 = {foo: 42}
    h2 = {'foo' => 42}
    def m(p); puts p.inspect; end
    m **h1
    #⇒ {:foo=>42}
    m **h2
    #⇒ TypeError: wrong argument type String (expected Symbol)
    
    推荐文章