I'm going through a Ruby tutorial, and learned that the code

puts 'start'
puts
puts 'end'

will output three lines, but the following code

puts 'start'
puts []
puts 'end'

will only output two. The stated reason is that [] isn't an object (edit: "doesn't point to anything"), so puts can't do anything with it, but why is that not also true in the first case?

I tried to find an official page about puts to figure this out, and this one was no help.

有帮助吗?

解决方案

The stated reason is that [] isn't an object

Stated where?

puts has a special handling for arrays. When you pass it an array, it prints each element on a new line. You pass it an array with zero elements, it prints zero lines.

其他提示

puts with an array will print one line per element. No element, no lines.

EDIT: What I just said is documented in your link:

If called with an array argument, writes each element on a new line.

The link your shared, states:

If called with an array argument, writes each element on a new line.

puts []

means, you are calling puts with empty array. i.e. no elements to print. and that's what happened.

puts arr

is like

arr.each { |e| puts e }

You can do something like this by yourself:

def p(s)
  if s.respond_to? 'each'
    s.each { |e| p e }
  else
    puts s
  end
end

p 'hello' # prints line with 'hello'
p [] # prints nothing
p [1, 2] # prints 2 lines with 1 and 2

Puts with no arguments has special behaviour - i.e. print new line. In all other cases, it treats all arguments as an array, and maps these arguments to strings using #to_s, and outputs each string on a new line. That's why you get no output when calling puts []. If you want to have a new line in the output, you can either call puts with no arguments (it's obvjous), or use splat operator with empty array, like this: puts *[].

You can write your own implementation of puts in order to understand things better.

  def my_puts(*args)
    STDOUT.write("args is #{args.inspect}\n")
    if args.empty?
      STDOUT.write("\n")
    else
      args.each { |arg| STDOUT.write("#{arg.to_s}\n") }
    end
  end


1.9.3p194 :039 > my_puts
args is []

 => 1 
1.9.3p194 :040 > my_puts []
args is [[]]
[]
 => [[]] 
1.9.3p194 :041 > my_puts *[]
args is []

 => 1 
1.9.3p194 :042 > my_puts 1,2,3
args is [1, 2, 3]
1
2
3
 => [1, 2, 3] 
1.9.3p194 :043 > my_puts [1,2,3]
args is [[1, 2, 3]]
[1, 2, 3]
 => [[1, 2, 3]] 
1.9.3p194 :044 > my_puts *[1,2,3]
args is [1, 2, 3]
1
2
3
 => [1, 2, 3] 
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top