简体   繁体   中英

Scalar and List context in Perl

1 @backwards = reverse qw(yabba dabba doo);
2 $backwards = reverse qw(yabba dabba doo);
3 
4 print @backwards; #gives doodabbayabba
5 print $backwards."\n"; #gives oodabbadabbay
6 print @backwards."\n"; #gives 3

In the above code why does line 6 give 3 as the output? Why does it convert to scalar context if its concatenated with a \\n?

Thanks

Line 6 gives 3 because the . operator imposes scalar context on both its operands, and @backwards in a scalar context yields 3 (because any array in a scalar context reports the number of elements in it).

Try:

print "@backwards\n";

To join the elements in an array, use join :

print join(', ', @backwards) . "\n";

Your question is ultimately "why is @backwards in scalar context in line 6", which begs the question, "how can I determine a term's context?".

Context is determined by "what is around" (ie its "context") the term.

How can I determine a term's context? By looking at the operator/function that is using the term.

What steps could you follow to figure out the context for @backwards yourself if you didn't have helpful stackoverflow folks around to tell you its context?

Here we have

print @backwards."\n"

so there are two operators/functions. How do we know which one provides context to @backwards? By consulting precedence. Near the top of perlop.pod we have Perl's precedence chart (print is a "list operator"):

left    terms and list operators (leftward)
...
left    + - .
...
nonassoc    list operators (rightward)

Oh great, now we need to know whether print is leftward or rightward. By consulting the "Terms and List Operators (Leftward)" section in perlop (right after the precedence list) we see that print is rightward here, because we have not enclosed its arguments in parenthesis.

So concatenation is higher precedence, so concatenation provides context to @backwards.

Next step is to check the docs (perlop again) for concatenation:

Binary "." concatenates two strings.

Strings are scalars, so binary "." concatenates two scalars.

And we finally have it!

@backwards has scalar context because concatenation provides scalar context to each of its operands.

Woo. That was easy, wasn't it :-)

Context is tricky. And sometimes a couple of pixels can make all the difference. Consider the following two lines:

print localtime, "\n";
print localtime. "\n";

Did you spot the difference?

The two statements look really similar. But what it going on in the two cases is very different.

In the first statement, print is passed a list of arguments. And the documentation for print says that it imposes list context on its arguments. Therefore the call to localtime is evaluated in list context and the function returns a list of numbers.

In the second statement, print receives a single argument. That argument is a string created by concatenating the results of calling localtime with a newline character. The concatenation operator imposes scalar context on both of its operands. Therefore the call to localtime returns the current time in a human-readable string format. That string is then concatenated with the newline and the resulting string is passed to print. The print call still evaluates its argument in list context, but that context makes no difference to the way that the single string argument is interpreted.

For another, similar, look at the weirder corners of context in Perl, see the question I posted on my blog a couple of days ago. I'll be posting the solution in a few days time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM