免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
1234下一页
最近访问板块 发新帖
查看: 18388 | 回复: 36
打印 上一主题 下一主题

mlists一位大侠对上下文概念的阐述 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-03-09 13:30 |只看该作者 |倒序浏览
大家对Perl的上下文概念有所迷惑的,当认真读此前辈名言.

>@string_array = <STDIN>;
>
>@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.



偶亦希望学Perl者,一定要弄清楚上下文这个基本概念.

论坛徽章:
0
2 [报告]
发表于 2007-03-09 13:37 |只看该作者
thanks 学习了

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
3 [报告]
发表于 2007-03-09 14:18 |只看该作者
认真的读一下

论坛徽章:
0
4 [报告]
发表于 2007-03-10 12:43 |只看该作者
thanks very much

论坛徽章:
0
5 [报告]
发表于 2007-03-10 22:51 |只看该作者
明白了表达的意思,只是不明白为什么会这样
print("\n" . reverse(@string_array) . "\n");
这一句居然reverse 了list本身顺序,因为分格符reverse 了 list中的元素倒是可以理解,
难道这个要强记下来么

论坛徽章:
0
6 [报告]
发表于 2007-03-10 23:57 |只看该作者
原帖由 penny_kan 于 2007-3-10 22:51 发表
明白了表达的意思,只是不明白为什么会这样
print("\n" . reverse(@string_array) . "\n");
这一句居然reverse 了list本身顺序,因为分格符reverse 了 list中的元素倒是可以理解,
难道这 ...


没听明白,想要表达what?

论坛徽章:
0
7 [报告]
发表于 2007-03-11 09:56 |只看该作者
参考:
perl cookbook 2nd
Recipe 1.7 Reversing a String by Word or Character

论坛徽章:
0
8 [报告]
发表于 2007-03-11 12:45 |只看该作者
原帖由 兰花仙子 于 2007-3-10 23:57 发表


没听明白,想要表达what?


print("\n" . reverse(@string_array) . "\n");
没明白这句为什么会把list与scalar都reverse一遍。
举例,如果代码是这样

@string_array = qw#how are you#;        

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


事实第二句的输出内容是
woherauoy
而我的理解是第二句应该输出为
uoyerawoh


~

论坛徽章:
0
9 [报告]
发表于 2007-03-11 23:19 |只看该作者
我好像没有义务教你们什么是上下文。

[ 本帖最后由 shhgs 于 2008-1-24 21:45 编辑 ]

论坛徽章:
0
10 [报告]
发表于 2007-03-12 18:40 |只看该作者
原帖由 penny_kan 于 2007-3-11 12:45 发表


print("\n" . reverse(@string_array) . "\n");
没明白这句为什么会把list与scalar都reverse一遍。
举例,如果代码是这样



事实第二句的输出内容是
woherauoy
而我的理解是第二 ...



这是因为reverse这个函数本身区分上下文环境.不同上下文返回值不同.
from perldoc -f reverse:
       reverse LIST
               In list context, returns a list value consisting of the elements of LIST in the opposite order.  In scalar
               context, concatenates the elements of LIST and returns a string value with all characters in the opposite
               order.

                   print reverse <>;           # line tac, last line first

                   undef $/;                   # for efficiency of <>
                   print scalar reverse <>;    # character tac, last line tsrif
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP