Giorgio Ghiatis
Giorgio Ghiatis

Reputation: 2130

Can a var concatenated to a string be manipulated by reference

I need to initialize a string with a fixed text concatenated to a variable like this:

   my $id = 0;
   my $text ="This is an example, id: ".$id."\n";

Now, in a imaginay loop for 0->9, I want to modify only the $id value without changing the fixed text. I guessed that using references should work like this way

for($i = 0; $i < 9; $i++) {
    my $rid = \$id;
    ${$rid}++;
    print $text;
}

Wanted output is

This is an example, id: 0
This is an example, id: 1
This is an example, id: 2

and so on...but it's not working.

Am I misunderstanding referencing system?

Upvotes: 0

Views: 99

Answers (3)

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118128

You seem to be confused about references. Maybe you are thinking thinking of the following C pointer scenario:

char text[] = "This is a test xx\n";
char *cursor = text + 15;
*cursor = ' 1';

I don't know what thought process can bring about the impression that once you interpolate the contents of $id into my $x = "Test string $id", you can change the value of the interpolated string by changing the value of $id.

As I said, you really are confused.

Now, if you want a subroutine someplace to be able to format some output without embedding in the subroutine the output format, you can pass as one of the arguments to the subroutine a message formatter as in:

my $formatter = sub { sprintf 'The error code is %d', $_[0] };

forbnicate([qw(this that and the other)], $formatter);

sub frobnicate {
    my $args = shift;
    my $formatter = shift;

    # ...

    for my $i (0 .. 9) {
       print $formatter->($i), "\n";
    }

    return;
}

This is bound to get tedious, so you can basically have a package of formatters, and let subs use whatever formatters they need:

package My::Formatters;

sub error_code {
    my $class = shift;
    return sprintf 'The error code is %d', $_[0];
}

In the main script:

use My::Formatters;

for my $i (0 .. 9) {
    My::Formatters->error_code($i);
}

Upvotes: 1

imran
imran

Reputation: 1560

As Sinan pointed out there is an easier way to do this. If you want to keep the $text string separate for maintainability and/or reuse, you may also consider using sprintf, e.g.:

my $id = 0;
my $max_id = 9;
my $text = "This is an example, id: %d\n";

for (my $i = $id; $i < $max_id; $i++) {
    print sprintf($text, $i+1);
}

Upvotes: 1

user1937198
user1937198

Reputation: 5348

You are missunderstanding the reference system.

with

my $id = 0;
my $text ="This is an example, id: ".$id."\n";

The text is concatinated with the value of id at that point, in this case 0. This text loses all connection with the varable $id. Then in the loop

for($i = 0; $i < 9; $i++) {
    my $rid = \$id;
    ${$rid}++;
    print $text;
}

You are incrementing the $id variable using $rid( which in becomes another name for $id at my $rid = \$id; but this will have no affect on the text as it has no reference to the variable $id.

The cleanest way of doing what your trying to do is to use a closure

my $id = 0;
my $textfunc = sub { return "This is an example, id: ".$id."\n" };

then in your loop do

for($i = 0; $i < 9; $i++) {
    $id++;
    print $textfunc->();
}

Upvotes: 3

Related Questions