Ruby中reduce方法默认初始值的决策位置咨询
reduce Acts Like It Has Default Initial Values for :+ and :* Great question! Let’s clear up this common misconception—Ruby doesn’t actually have a lookup table that assigns 0 as the default for addition or 1 for multiplication in reduce. Instead, it’s all about how reduce handles the absence of an explicit initial value, combined with the mathematical properties of those operations.
Here’s the breakdown:
- When you call
reducewithout an initial value (like(5..10).reduce(:+)), Ruby does not start with0or1. Instead, it takes the first element of the enumerable as the starting "memo" value, then iterates over the remaining elements to apply the operation.- For
(5..10).reduce(:+), that means starting with5, then adding6,7, ...,10—resulting in45, which matches the outcome of starting with0(since0is the additive identity:0 + x = x). - For
(5..10).reduce(:*), it starts with5, multiplies by6, ...,10—resulting in151200, same as starting with1(the multiplicative identity:1 * x = x).
- For
The difference becomes obvious with empty enumerables
If you try reduce without an initial value on an empty enumerable, Ruby throws an error—because there’s no first element to use as the starting memo:
# Raises LocalJumpError: no block given (yield) (1..0).reduce(:+) # Works as expected, returning the additive identity (1..0).reduce(0, :+) # => 0
Same logic applies to multiplication:
# Raises LocalJumpError (1..0).reduce(:*) # Returns the multiplicative identity (1..0).reduce(1, :*) # => 1
Digging into the C source (enum.c)
In the enum_reduce function, the core logic hinges on how many arguments you pass:
- If you only pass the operation (no initial value), it first calls
rb_enum_nextto grab the enumerable’s first element as the memo. If the enumerable is empty, this call triggers aStopIterationexception, which gets converted to aLocalJumpError. - If you provide an initial value, it uses that as the starting memo and iterates over all elements of the enumerable.
There’s no hardcoded mapping for :+ or :*—the "default" behavior you observed is just a side effect of mathematical identities aligning with the result of starting with the enumerable’s first element.
内容的提问来源于stack exchange,提问作者Jed Schneider

