Chinaunix首页 | 论坛 | 博客
  • 博客访问: 233193
  • 博文数量: 97
  • 博客积分: 1440
  • 博客等级: 上尉
  • 技术积分: 821
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-28 13:45
文章分类

全部博文(97)

文章存档

2011年(3)

2010年(4)

2009年(7)

2008年(2)

2007年(8)

2006年(73)

我的朋友

分类:

2011-09-04 18:54:20

下面这个帖子把perl的两种context讲得很透彻,特此转载与此,便于更多的人看到。

QUOTE:
>@string_array = ;
>
>@string_array = reverse(@string_array);
>print("\n@string_array\n");
>print("\n" . reverse(@string_array) . "\n");
>
>
>If this is run, the first print statement prints out the lines in the
>opposite order they were entered, however the second print statement
>reverses the entire line one at a time. I do not understand what is
>going on. 


That is a very good question, and it goes right to the heart of a very important and unusual feature of the Perl language, so it'll take a little while to explain. Please bear with me through this explanation of one of Perl's central concepts. 

Every Perl expression is in one of two `contexts', either `list context' or `scalar context', depending on whether it is expected to produce a list or a scalar. Many expressions have quite different behaviors in list context than they do in scalar context.

Here is a typical expression:

        EXPRESSION

Here it is again, in a list context:

        @array = EXPRESSION;   # Expression is expected to produce a list

Here is how it looks in a scalar context:

        $scalar = EXPRESSION;   # Expression is expected to produce a scalar

The values that a particular expression has in these two contexts might be quite different. For example, consider this simple expression:

        @q

In list context, this produces a list of the items in the array @q, but in scalar context it produces the number of items in the array @q.

        @a = @q;    # @q in list context produces a list of items from @q
        $s = @q;    # but in scalar context, it produces the number of items.

Similarly, 

        # Note two very different behaviors of // depending on context

        # Put ('123.45', 'immediately') into @a
        @a = /The amount was \$(\d+\.\d\d)\.  You must pay ([\w\s]+)\./ 

        # Put 1 into $s, put '123.45' into $1, put 'immediately' into $2
        $s = /The amount was \$(\d+\.\d\d)\.  You must pay ([\w\s]+)\./ 

The main point here: An expression's behavior can be drastically different in list context than it is in scalar context.

Now we'll return to your example.


>     @string_array = reverse(@string_array);

Here, reverse is in list context, because it's being asked to produce a list to assign to @string_array. In list context, reverse reverses the order of its arguments, so that the lines come out in the reverse order. 

Then you did

>    print("\n" . reverse(@string_array) . "\n");

Now, here reverse is in scalar context, because it is being asked to produce a scalar value, a string, which will be concatenated with \n on the front and back. In a scalar context, reverse first concatenates all its arguments, to get a single string, and then reverses that string. As you know by now.

How can you get the behavior you really want? The reverse here needs to be in a list context. The argument list of a function like `print' is always a list context, so if you get rid of the concatenation operators that are providing scalar context to `reverse', your problem will go away:

        print "\n", reverse(@string_array), "\n";

reverse is now expected to return a list, which will be inserted into the list which is passed to print. This is probably more efficient than what you were trying to do anyway, since print can print out the many strings without bothering to concatenate them first, as you were doing.

Again, the general rule is:

There is no general rule for deducing a function's behavior in scalar context from its behavior in list context. 
This is the cause of a lot of common errors. One mistake you didn't make, but which we see a lot is something like this:

        @a = (reverse("part"));

The programmer was expecting @a to get a list containing "trap", but instead they got a list containing "part" again. Because reverse was in a list context, it reversed the order of its arguments, instead of reversing the arguments themselves, and since it only had one argument, it ended up doing nothing.

Perl has a special operator for just such circumstances. It's called scalar, and it forces its argument to be evaluated in scalar context. The last example should have been written as:

        @a = (scalar(reverse("part")));
        # @a now contains ("trap")

I hope this clears things up for you.
阅读(1192) | 评论(0) | 转发(0) |
0

上一篇:王家字辈

下一篇:没有了

给主人留下些什么吧!~~