Почему `$ 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)) (который имеет только один элемент)
Изменить: неправильная запись массива, и результат был неправильным из-за последней минуты изменения моего тестового сценария