4.5 拆聚

Ruby Javascript ES5 Javascript ES6 Go Lua
并行赋值 Y N Y Y Y
函数参数拆聚 Y 伪数组arguments Y Y Y
函数多返回值 Y N N Y Y

多值的拆解/聚合主要可以用在:

  • 并行赋值/解构赋值
  • 函数变长参数列表
  • 数组展开为多个实参
  • 函数多返回值

在ruby, ES6中都有拆聚操作符, ruby中是*, ES6中是..., 表现形式基本一致:

  • 拆聚操作符+变量: 表示将把传入/匹配的多个单值, 聚合为一个数组, 赋给此变量
  • 拆聚操作符+数组: 表示数组将被展开多个单值

Go, Lua 的函数多返回值, 是分离的值, 可以作为另外一个函数的调用实参, 或者赋给右值, Ruby的函数多返回值, 是聚合到一个数组里, 也可以赋值给右值, 但是如果希望作为另一个函数的调用实参, 需要按需打散.


1. Ruby

  • 并行赋值:

    x, y, z = 1, 2, 3
    x, y, z = [1, 2, 3] #同上
    x = 1, 2, 3         # x = [1, 2, 3]
    x, = 1, 2, 3        # x =1 类似模式匹配
    x, y = 1, 2, 3      # x=1, y=2 多余的右值丢弃
    x, y, x = 1, 2      # x=1, y=2, z=nil 匹配不成功的就是nil
    x, (y, z) = a, b    # x = a; y, z = b
    
    • 赋值聚合

      x, *y, z = 1, 2, 3, 4      # x=1, y=[2, 3], z=4
      
    • 函数变长参数列表

      def max(first, *rest) # * 起到聚合多个实参的作用
        max = first
        rest.each {|x| max = x if x > max}
        max
      end
      max(1, 2, 3) #3
      
    • 赋值展开

      x, y, z, k = 1, *[2, 3], 4 # x, y, z, k = 1, 2, 3, 4
      

      不过拆聚操作符*some_value 不能作为独立的表达式而存在

    • 数组拆为多个实参

      data = [1, 2, 3]
      m = max(*data)
      

2. Javascript

ES5: 伪数组arguments可以用于实现变长参数列表

ES6:

  • 并行赋值

    let [a, b, c] = [1, 2, 3];
    let [foo, [[bar], baz]] = [1, [[2], 3]]; //foo=1, bar=2, baz=3 基于模式匹配
    let [x, , y] = [1, 2, 3];                // x=1, y=3 基于模式匹配
    let [x, y] = [1, 2, 3];                  // x=1, y=2 多余右值丢弃
    let [x, y] = ['a'];                      //x="a", y=undefined  匹配不到就是undefined
    
  • 聚:

    • 赋值聚合

      const [head, ...tail] = [1, 2, 3, 4];   //head=1, tail=[2, 3, 4]
      
    • 函数变长参数列表

      const getOptions = function(...args){ //args真数组
      
  • 拆:

    • 赋值展开

      const opts = ['one', 'two', 'three', 'four'];
      const config = ['other', ...opts];
      
    • 数组拆为多个实参

      const numbers = [1, 2, 3];
      max(...numbers);
      

3. Go

  • 并行赋值

    x, y := 1, 2
    
  • 拆:

    append([]byte("abc"), "xyz"...)         //拆字符串
    append([]byte("abc"), []byte("abc")...) //拆数组
    
  • 聚:

    func (slice_inside ...int)
    

4. Lua

  • 并行赋值

    a, b = 10, 20
    
    • 函数变长参数列表:

      function select (n, ...)
        return arg[n]
      end
      
      select(2, 10, 20, 30) -- 20
      

      变成参数聚合到指定命名的table arg中, arg中还有一个域n表示参数的个数

    • 数组拆为多个实参, 利用内置函数unpack

      data = {10, 20, 30}
      select(2, unpack(data)) -- 20
      

      在5.2中使用table.unpack, 也可以手动指定需要的范围.

      table.unpack({10, 20, 30}) -- 10 20 30
      
      print(table.unpack({10,20,30,40}, 2, 3)) -- 20, 30 左闭右闭
      
  • 函数多返回值

    function foo0 () end
    function foo1 () return 'a' end
    function foo2 () return 'a','b' end
    
    x,y = foo2()         -- x='a', y='b'
    x = foo2()           -- x='a', 'b' is discarded
    x,y,z = 10,foo2()    -- x=10, y='a', z='b'
    x,y = foo0()         -- x=nil, y=nil
    x,y = foo1()         -- x='a', y=nil
    x,y,z = foo2()       -- x='a', y='b', z=nil
    
    x,y = foo2(), 20     -- x='a', y=20
    x,y = foo0(), 20, 30 -- x='nil', y=20, 30 is discarded
    

    如果做为另一个函数的参数的函数调用不是最后一个参数的话, 此函数返回值将只有第一个; 多值函数在表达式中会自行调整适应.

    特别的是, 函数调用可以直接用于初始化table, 同样的, 只有最后一个函数调用的多值才完全保留, 其他位置的多值只保留第一个.

    a = {foo0()}  -- a = {} (an empty table)
    a = {foo1()}  -- a = {'a'}
    a = {foo2()}  -- a = {'a', 'b'}
    
    a = {foo0(), foo2(), 4} -- a[1] = nil, a[2] = 'a', a[3] = 4
    

    多返回值可以使用()保留第一个值:

    print((foo2())) --> a
    

results matching ""

    No results matching ""