Можно ли имитировать макрос в стиле C в Perl? - PullRequest
3 голосов
/ 20 февраля 2012

Код:

my $tmp='x $i y';  # define a macro or whatever

for my $i (0..5){
    my $var;
    #    eval { $var=$tmp; };       # A
    #    eval { $var="x $i y"; };   # B
    $var="x $i y";                  # C
    print $var."\n";
}

B и C напечатает

x 0 y
x 1 y
x 2 y

Печать

x $i y
x $i y
x $i y

Что не так в A?

Ответы [ 4 ]

2 голосов
/ 20 февраля 2012

eval BLOCK только ловит исключения, так что это не имеет отношения к вопросу. Это оставляет нам следующий код:

my $i;
my $tmp = 'x $i y';
$i = 3;
my $var = $tmp;

В обоих случаях правая часть назначения - одна и та же строка, так почему вы ожидаете, что $tmp и $var будут иметь разные значения? Это не имеет смысла.

Так как же решить вашу проблему? Если вы хотите, чтобы содержимое $tmp использовалось в качестве кода Perl, вам необходимо использовать eval EXPR, а содержимое $tmp на самом деле должно быть кодом Perl.

my $i;
my $tmp = '"x $i y"';   # Quotes added to make it valid Perl.
$i = 3;
my $var = eval $tmp;    # eval EXPR instead of eval BLOCK.

Но это так плохо. Вы используете eval EXPR в качестве системы шаблонов. Используйте настоящую временную систему, такую ​​как Template-Toolkit . Но если вы хотите продолжать использовать шаблоны вида x $i y, посмотрите на String :: Interpolate .

2 голосов
/ 20 февраля 2012

Если вы наберете $tmp, он просто вернет строку внутри него, что означает, что вы сделаете: $var = 'x $i y'. Вам нужно проверить строку в $tmp, но не $var. Кроме того, вы не можете напрямую оценить строку, вам нужно заключить ее в двойные кавычки, чтобы разрешить интерполяцию $i, например:

$tmp = '"x $i y"';  # note double quotes inside
...
$var = eval $tmp;

Однако, eval - довольно грубое решение любой такой проблемы. В большинстве случаев вы думаете, что вам это нужно, вам нужно подумать еще раз. Ваше решение может быть ссылками на код:

my $tmp = sub { my $num = shift; return "x $num y" };

for my $i (0 .. 5) {
    print $tmp->($i);
}

Здесь вы не будете пытаться использовать фактический аргумент $i в цикле for, а вместо этого передадите $i в качестве аргумента для подпрограммы, которая использует его и возвращает строку.

0 голосов
/ 20 февраля 2012

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

Теперь что касается "создания макроса", то, что вы пытались сделать. Вот способ сделать это на Perl, но, честно говоря, код, который вы пишете, никогда не должен делать такие вещи.

use strict;

# This is your "counter" variable
my $i = 0; 

# This is your "Macro"
my $macro = sub{ return 'x ' . ${\$i} . ' y'}; 

for my $x (0..5){

    $i = $x;
    print &{$macro}, "\n";

}

Результат:

x 0 y
x 1 y
x 2 y
x 3 y
x 4 y
x 5 y
0 голосов
/ 20 февраля 2012

Имена переменных в строках в двойных кавычках заменяются значениями, переменные в строках в одинарных кавычках , а не (это называется интерполяция ). Вот почему параметры A печатают $i вместо значения.

A делает то же самое, что и

my $var = 'x $i y';
print $var."\n";     # prints 'x $i y\n';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...