*在范围开始时是什么意思?

时间:2019-04-28 08:29:50

标签: arrays ruby range

很抱歉出现noob问题,但是这个星号在范围开始时是什么意思?

class Matrix
  def initialize(matrix_string)
    @matrix = matrix_string.split("\n").map do |row|
        row.split.map(&:to_i)
    end
    @rows = rows.length
    @cols = columns.length
  end

  def rows
    @matrix
  end

  def columns
    @matrix.transpose
  end

  # --->>***
  def saddle_points
    [*0...@rows].product([*0...@cols]).select do |coords|
        saddle_point?(*coords)
  end
  # ***<----
end

private
  def   saddle_point?(row, col)
    (@matrix[row][col] == rows[row].max) && 
    (@matrix[row][col] == columns[col].min)
  end
end

3 个答案:

答案 0 :(得分:2)

in the documentation所述:

  

您可以使用Array(或splat)运算符将*转换为参数列表:

arguments = [1, 2, 3]
my_method(*arguments)

Range可以这样做:

arguments = 1..3
my_method(*arguments) # essentially the same as my_method(1, 2, 3)

在数组声明内的范围之前也允许使用splat运算符将Range隐式转换为Array

[*1..3]
#⇒ [1, 2, 3]

答案 1 :(得分:1)

*通过“拆分”其内容并将其转换为数组来解压缩数组。

答案 2 :(得分:1)

如其他答案所述,*运算符用于将数组转换为参数列表。

但是,如果您的对象不是数组,该怎么办?然后,Ruby将在对象上调用#to_a(如果已定义),并改用返回的数组。否则,将使用对象本身。

在这种情况下,对象既不是数组也不定义#to_a

x = *4 # => [4]

如果对象定义了#to_a,则将像Range那样调用和使用该对象:

x = *0..1 # => [0, 1]

为了证明这一点,我们可以在模块之前添加一个跟踪到#to_a的调用:

module Trace
  def to_a
    puts "#to_a called"
    super
  end
end

Range.prepend(Trace)

x = *0..1
# prints "#to_a called"
# => [0, 1]

请注意,如果您的对象已经是#to_a类型,那么Ruby将不会调用Array

我们也可以在自定义类型上使用它:

class Foo
  def to_a
    [1, 2, 3]
  end
end

x = *Foo.new # => [1, 2, 3]

顺便说一句,Ruby的nil也实现了#to_a。这使我们可以像传递任何内容一样传递nil作为参数,因为nil.to_a返回[]

def count(*args)
  args.count
end

count # => 0
count(*0..1) # => 2
count(*nil) # => 0

当您将一个可能为nil的变量传递给具有默认值的方法时,这很有用:

def say_hi(name = "Jane")
  puts "Hi, #{name}"
end

name = nil
say_hi(*name) # prints "Hi, Jane"

但是,如果我们删除NilClass#to_a

NilClass.undef_method(:to_a)

say_hi(*name) # prints "Hi, "