Scalar vs list context in Perl

帅比萌擦擦* 提交于 2019-12-05 05:37:06

问题


I found an example in an O'Reilly book a little weird:

@backwards = reverse qw/ yabba dabba doo /;
print "list context: @backwards\n";
$backward = reverse qw/ yabba dabba doo /;
print "scalar1 context: $backward\n";
$notbackward = qw/ yabba dabba doo /;
print "scalar2 context: $notbackward\n";
print "print context: ",reverse qw/ yabba dabba doo /;
print "\n";

The output is:

list context: doo dabba yabba
scalar1 context: oodabbadabbay
scalar2 context: doo
print context: doodabbayabba

The one I do not understand is the scalar1 context:

The book says 'reverse something' gives a list context, so I guess qw/ yabba dabba doo / is seen as a list and reverse qw/ yabba dabba doo / as ('doo', 'dabba', 'yabba').

So comes the $backward = something which implies something is a scalar, so I was expecting the result 'doo dabba yabba', but it is différent: 'oodabbadabbay'.

I thought, the reason was because one cannot set a list to a scalar directly. So I made the scalar2 test: only the latest item in the list is printed. Why? Why not in the scalar1 test?

How do the scalar tests output work?


回答1:


For the line:

$backward = reverse qw/ yabba dabba doo /;

You are requesting a scalar here from reverse. The perldoc for reverse says:

In scalar context, concatenates the elements of LIST and returns a string value with all characters in the opposite order.

So it returns each of the letters reversed.

For $notbackward = qw/ yabba dabba doo /; the perldoc for qw// says:

Evaluates to a list of the words extracted out of STRING, using embedded whitespace as the word delimiters. It can be understood as being roughly equivalent to:

               split(’ ’, q/STRING/);

the differences being that it generates a real list at compile time, and in scalar context it returns the last element in the list.

So requesting the scalar only returns the last item in the list.




回答2:


First of all, qw/ yabba dabba doo / is just syntactic sugar for ('yabba', 'dabba', 'doo'). They mean the same thing.

The reverse function takes a list. In list context, it reverses the list. In scalar context, it does join('', @list) and then reverses the characters in that string and returns it.

Remember that

$backward = reverse qw/ yabba dabba doo /;
$notbackward = qw/ yabba dabba doo /;

means

$backward = reverse ('yabba', 'dabba', 'doo');
$notbackward = ('yabba', 'dabba', 'doo');

The reverse function supplies list context and $notbackward = gives us scalar context. This means that the comma operator is in list context on the first line and scalar context on the second. In list context, the comma operator creates a list. In scalar context, it evaluates both operands and returns the right hand one. This means that the value of ('yabba', 'dabba', 'doo') in scalar context is 'doo', and that's what's assigned to $notbackward.




回答3:


All Perl functions, including any sub's that you define, can detect whether they are being called in "scalar" or "list" context, and there are many functions that change their behavior based on this context.

There are very few conventions, other than Do What I Mean, about when and how a function treats the two contexts differently (this whole thread on perlmonks has a good discussion of these issues), so you need to rely on the documentation of each function to guess what a function will do in a particular context.

Specifically for your four examples,

1. @backwards = reverse qw/ yabba dabba doo /
2. $backward = reverse qw/ yabba dabba doo /
3. $notbackward = qw/ yabba dabba doo /;
4. print ..., reverse qw/ yabba dabba doo /;

the behaviors are

1. reverse function, list context:     returns list of the elements in reverse order

2. reverse function, scalar context:   concatenate argument list to a string,
                                       return reverse of that string

3. list assignment to scalar:          returns last element in list (*)

4. also reverse function, list context    same as #1

(*) - note list assignment to scalar is different from array assignment to scalar -- this is one of the most important distinctions between lists and arrays:

@a = ("x", "y", "z");  $n = @a;   # array assignment,  $n is array size, or "3"
$n = ("x", "y", "z");             # list assignment,   $n is last element, or "z"



回答4:


To simplify the other answers, reverse actually does two separate things, list reversal and string reversal.

This has proven to be so confusing that perl6 splits them out to differently named functions.



来源:https://stackoverflow.com/questions/5170720/scalar-vs-list-context-in-perl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!