Почему `$ v =() = split` return 1?

perldoc говорит: "назначение списка в скалярном контексте возвращает количество элементов в правой части назначения списка", но когда я пробую этот код:

perl -e '$_="aaaaa";print $v=(()=split //)'

Вывод 1, который меня смущает. (Ответ, который я ожидаю, 5.)

Может кто-нибудь объяснить это?

Ответ 1

Согласно документации split:

При назначении списку, если LIMIT опущен или равен нулю, Perl LIMIT один больше, чем число переменных в списке <... >

Поскольку вы указываете пустой список, split возвращает только 1 результат, и это число результатов точно совпадает с вашей переменной.

Ответ 2

split имеет в себе какую-то сумасшедшую ультрамагию, которая позволяет ему знать, когда она находится в правой части задания, имеющего список слева, и корректирует его поведение в соответствии с номером элементов в этом списке.

Это описано в perlfunc как делается "во избежание ненужной работы", но вы обнаружили заметную разницу в поведении, вызванную этой оптимизацией.

Чтобы узнать, что произошло, запустите script через Deparse следующим образом:

perl -MO=Deparse -e '$_="aaaaa";print $v=(()=split //)'

Обновление. Я пошел искать код, который реализует это, и не там, где я ожидал, что это будет. Фактически оптимизация выполняется оператором присваивания (op.c:Perl_newASSIGNOP). раскол не знает о его контексте.

Ответ 3

Почему вы назначаете пустой массив? бит ()=(split //). Это будет в конечном итоге - гм, ну, беспорядок. Или, в вашем случае, массив с размером одного с небольшим количеством в нем.

Кроме того, это чрезмерно неясно. perl имеет печальную репутацию за то, что он только для записи, и все, что модифицирует $_ и использует его, не помогает другим - или вы - понимаете, что происходит.

Попробуйте что-нибудь вроде

perl -e '$v = (split //, "aaaaa"); print "$v\n"'

или, если вы хотите воспроизвести поведение вашего теста:

perl -e '$v = () = (split //, "aaaaa"); print "$v\n"'

Ответ 4

Да, но:

perl -e '$_="aaaaa";print $v=(split //)'

дает 5, а также

perl -e '$_="aaaaa";print $v=(@x=split //)'

Возможно, ваше левое значение() удаляет дополнительные элементы массива?

изменить: кстати:

perl -e '$_="aaaaa";print $v=(($x,$y)=split //)'

возвращает 3, так как правильный вид команды $v =... дает:

($ x, $y, (a, a, a))

Итак, в вашем исходном случае ()=split // возвращает ((a, a, a, a, a)) (который имеет только один элемент)

Изменить: неправильная запись массива, и результат был неправильным из-за последней минуты изменения моего тестового сценария