What exactly are “$a” and “$b” in Perl's “sort

2019-01-23 16:53发布

I understand how to get the results I want from using Perl's sort() function, this is more a question about the inner workings of sort().

Where do the "$a" and "$b" variables come from? I read through the documentation for sort and it seems unclear. What are "$a" and "$b" and what makes them special?

ex:

my @sorted_list = sort {$a cmp $b} @unsorted_list;

How does sort know what to do with "$a" and "$b" and why don't you get the "Global symbol requires explicit package name" error for "$a" or "$b"?

3条回答
放荡不羁爱自由
2楼-- · 2019-01-23 17:14

$a and $b are exempt global variables; they are exempt in that Perl allows them to be used (anywhere) without being declared. They are set by the sort function. Use of any other undeclared global in sort (in strict mode) will trigger an error.

The sort function accepts various forms of input, one being a code block, which is the form you are referring to.

{$a cmp $b} is a code block, it is parsed and passed as a "chunk of code" to the sort function, and Perl checks the arguments for sort and if it receives a code block, sort will set $a and $b, if they exist as package globals within the code block, and assign each pair of items being sorted to $a and $b. All you have to do is refer to them to control the sort algorithm. Otherwise, the internal algorithm is used (which I think is merge sort).

http://perldoc.perl.org/functions/sort.html

$a and $b are not lexicals, they are package globals (or just globals).

In a main you can write:

sort {$main::a cmp $main::b} @list;

Or in another package, you could write:

package foo;

sort {$foo::a cmp $foo::b} @list;

You shouldn't actually prefix like this; I am demonstrating that $a and $b are actually globals within your current package, and not some magic $a within the sort function, although Perl knows to allow you to define them even with strict mode.

You can't just use any variables (in strict mode). Try:

sort {$A cmp $B} @list;

Global symbol "$A" requires explicit package name at sort.pl

You cannot use a lexical (my $a) in scope of sort.

my $a;
sort {$a cmp $b} @list;

Can't use "my $a" in sort comparison at sort.pl line 13.

$a and $b are special anywhere in Perl. They are exempt from strict mode, which is unrelated to sort, though sort was the reason for the exemption.

查看更多
地球回转人心会变
3楼-- · 2019-01-23 17:19

What exactly are “$a” and “$b” in [the compare code of] Perl's “sort()” function?

Two values from the list of values to sort. The block is to return information as to how one should be positioned to the other in the final result.

What are "$a" and "$b" and what makes them special?

Package variables, and there's nothing special about them except that use strict 'vars'; does not consider using them to be an error.

Where do the "$a" and "$b" variables come from?

They are populated by sort.

How does sort know what to do with "$a" and "$b"

It doesn't do anything with them except populate them as required to perform its function.

why don't you get the "Global symbol requires explicit package name" error for "$a" or "$b"?

That would make it rather hard to use them!

What happens if you define a local variable, my $a or my $b, and then try and use sort within a scope where those [lexical] variables are visible?

If your compare function is in scope of a my $a and/or my $b, it will use those variables instead of the package variables sort populates.

Perl realizes you might be an easy mistake to make, so it checks for it.

$ perl -c -e'sort { my ($a,$b); $a cmp $b } @a;'
Can't use "my $a" in sort comparison at -e line 1.
查看更多
放我归山
4楼-- · 2019-01-23 17:27

The other answers are good, so I won't repeat, but one part of your question wasn't really answered.

Where do the "$a" and "$b" variables come from?

As codenheim wrote, sort is basically reaching down into your module (whether it's an explicit module or the main module) and defining the variables in your scope. How? Simply by temporarily turning off strict refs and spelling out the fully qualified variable name. With that done, the variable can be accessed via ${$variable_name}.

my $pkgname = caller();
my $varname = "${pkgname}::a";
no strict 'refs';
${$varname} = value;

Note: I discovered this technique in the source for List::Util.

查看更多
登录 后发表回答