Perl переменные побочные эффекты - PullRequest
3 голосов
/ 28 января 2020

Я буду первым, кто признает, что Perl не моя сильная сторона. Но сегодня я наткнулся на этот фрагмент кода:

my $scaledWidth = int($width1x * $scalingFactor);
my $scaledHeight = int($height1x * $scalingFactor);
my $scaledSrc = $Media->prependStyleCodes($src, 'SX' . $scaledWidth);

# String concatenation makes this variable into a
# string, so we need to make it an integer again.
$scaledWidth = 0 + $scaledWidth;

Я мог бы упустить здесь что-то очевидное, но я не вижу в этом коде ничего, что могло бы заставить $scaledWidth превратиться в строку. Если каким-либо образом конкатенация в третьей строке не заставит Perl навсегда изменить тип $scaledWidth. Это кажется ... вонючим.

Я немного искал "perl побочные эффекты назначения" и подобные термины, но ничего не нашел.

Может кто-нибудь из вас Perl Гуру, скажите мне, действительно ли эта закомментированная строка кода что-нибудь делает? Меняет ли использование целочисленной переменной в выражении конкатенации тип этой переменной?

Ответы [ 2 ]

6 голосов
/ 28 января 2020

Это только немного полезно.

Perl может хранить скалярное значение в виде числа или строки, или обоих, в зависимости от того, что ему нужно.

use Devel::Peek;
Dump($x = 42);
Dump($x = "42");

Выходы :

SV = PVIV(0x139a808) at 0x178a0b8
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 42
  PV = 0x178d9e0 "0"\0
  CUR = 1
  LEN = 16

SV = PVIV(0x139a808) at 0x178a0b8
  REFCNT = 1
  FLAGS = (POK,pPOK)
  IV = 42
  PV = 0x178d9e0 "42"\0
  CUR = 2
  LEN = 16

Токены IV и IOK относятся к тому, как значение хранится в виде числа, и является ли текущее целочисленное представление действительным, тогда как PV и POK указывают на строковое представление и действительно ли это. Использование числительного c скаляра в строковом контексте может изменить внутреннее представление.

use Devel::Peek;
$x = 42;
Dump($x);
$y = "X" . $x;
Dump($x);

SV = IV(0x17969d0) at 0x17969e0
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 42

SV = PVIV(0x139aaa8) at 0x17969e0
  REFCNT = 1
  FLAGS = (IOK,POK,pIOK,pPOK)
  IV = 42
  PV = 0x162fc00 "42"\0
  CUR = 2
  LEN = 16

Perl будет легко преобразовывать одно в другое при необходимости, и редко требуется Perl программист должен беспокоиться о внутреннем представлении.

Я говорю редко, потому что существуют некоторые известные ситуации, когда внутреннее представление имеет значение .

5 голосов
/ 28 января 2020

Perl переменные не напечатаны. Любой скаляр может быть числом или строкой, в зависимости от того, как вы его используете. Есть несколько исключений, когда операция зависит от того, выглядит ли значение больше как число или строка, но большинство из них либо устарели, либо считаются плохими идеями. Большим исключением является случай, когда эти значения должны быть сериализованы в формат, который явно хранит числа и строки по-разному (обычно JSON), поэтому вам нужно знать, каким он должен быть.

Внутренние детали являются то, что SV (скалярное значение) содержит любое из значений, которые были связаны с его использованием в течение его жизни. Таким образом, ваш $ scaledWidth сначала содержит только IV (целочисленное значение) как результат функции int. Когда он объединяется, он использует его как строку, поэтому он генерирует PV (значение указателя, используемое для строк). Эта переменная содержит оба , это не один тип или другой. Таким образом, когда что-то вроде JSON кодировщиков должно определить, должно ли это быть число или строка, они видят оба во внутреннем состоянии.

Было три стратегии, которые JSON кодировщики приняли для разрешения эта ситуация. Первоначально JSON :: PP и JSON :: XS просто считали бы ее строкой, если она содержит PV, или другими словами, если она когда-либо использовалась в качестве строки; и как число, если оно имеет только IV или NV (двойной). Как вы упоминали, это приводит к чрезмерному количеству ложных срабатываний.

Cpanel :: JSON :: XS, форк JSON :: XS, который устраняет большое количество проблем вместе с более поздними версиями JSON :: PP используют другой heuristi c. По сути, значение все равно будет считаться числом, если у него есть PV, но PV соответствует IV или NV, которое оно содержит. Это, конечно, все еще приводит к ложным срабатываниям (пример: у вас есть строка «5», и вы используете ее в числовой операции), но на практике это гораздо чаще, чем вы хотите.

Третий Стратегия наиболее полезна, если вам нужно быть уверенным, какие у вас типы: будьте явными. Вы можете сделать это, переназначив каждое значение явным образом числом или строкой, как в найденном вами коде. Это назначает новый SV для $ scaledWidth, который содержит только IV (результат операции сложения), поэтому нет никакой двусмысленности. Еще один метод явного использования заключается в использовании метода кодирования, который позволяет указывать нужные типы, например Cpanel :: JSON :: XS :: Type .

Подробности, конечно, могут отличаться, если Вы не говорите о формате JSON, но именно здесь эта проблема была наиболее тщательно продумана. Это различие невидимо в большинстве кодов Perl, где тип, а не операция определяют тип.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...