解释Perl代码以KB,MB,GB等显示多个字节

时间:2016-05-09 19:36:30

标签: perl

给定一些字节,它将其格式化为“字节”,“KB”,“MB”或“GB”......但我不明白的是部分:

$_->[1], $_->[0]

不是传递给地图的一组哈希?那么怎么会有一个0和1的索引?

sub fmt {
    my $bytes = shift;

    return (
        sort { length $a <=> length $b                         } 
        map  { sprintf '%.3g%s', $bytes/1024**$_->[1], $_->[0] } 
        [" bytes"=>0],[KB=>1],[MB=>2],[GB=>3]
    )[0];
}

5 个答案:

答案 0 :(得分:7)

这是一段糟糕的代码。有人在炫耀

传递给map的列表是:匿名数组列表

[ " bytes" => 0 ], [ KB => 1 ], [ MB => 2 ], [ GB => 3 ]

虽然 fat逗号运算符=>经常出现在哈希文字的上下文中,但这并不是它的全部优点。它与普通逗号, 相同,但 bareword 左手操作数将被隐式引用。如果没有它,列表将与

相同
[ ' bytes', 0 ], [ 'KB', 1 ], [ 'MB', 2 ], [ 'GB', 3 ]

这里有相同的函数,中间map语句的结果扩展为一个单独的数组@variations,我使用Data::Dump转储它以显示它&#39;做

传递给map的列表是一些匿名数组 - 每个数组都包含后缀字符串以及该字符串对应的1024的相应功率。 return语句只选择最短的表示

use strict;
use warnings 'all';
use feature 'say';

use Data::Dump;

say fmt(987 * 1024**2);

sub fmt {
        my $bytes = shift;

        my @variations = map { sprintf '%.3g%s', $bytes/1024 ** $_->[1], $_->[0] }
            [ " bytes" => 0 ],
            [ KB => 1 ],
            [ MB => 2 ],
            [ GB => 3 ];

        dd \@variations;

        return ( sort { length $a <=> length $b } @variations ) [0];
}

输出

["1.03e+009 bytes", "1.01e+006KB", "987MB", "0.964GB"]
987MB

我通常使用类似的东西。 sprintf的滑稽动作是确保永远不会显示一个字节的分数

sub fmt2 {
    my ($n) = @_;
    my @suffix = ( '', qw/ K M G T P E / );

    my $i = 0;
    until ( $n < 1024 or $i == $#suffix ) {
        $n /= 1024;
        ++$i;
    }

    sprintf $i ? '%.3g%sB' : '%.0f%sB', $n, $suffix[$i];
}

答案 1 :(得分:4)

通过一点点数学,这可以在没有任何迭代或巧妙构造的数组的情况下完成:

my @si_prefix = ('', qw( K M G T P E Z Y ));
sub fmt {
  my $bytes = shift or return '0B';
  my $pow = int log(abs $bytes)/log(1024);
  return sprintf('%3.3g%sB', $bytes / (1024 ** $pow), $si_prefix[$pow]);
}

我们可以使用对数基本更改规则轻松确定1024的最接近功率:log 1024 ($ bytes)= log($ bytes)/ log(1024)

为了好玩,我使用问题代码来运行Benchmark::cmpthese,@ Borodin fmt2和我的版本:

Benchmarking 1B
                 Rate    fmt_orig fmt_borodin         fmt
fmt_orig     245700/s          --        -76%        -84%
fmt_borodin 1030928/s        320%          --        -34%
fmt         1562500/s        536%         52%          --

Benchmarking 7.45GB
                 Rate    fmt_orig fmt_borodin         fmt
fmt_orig     224215/s          --        -66%        -84%
fmt_borodin  653595/s        192%          --        -54%
fmt         1428571/s        537%        119%          --

Benchmarking 55.5EB
                 Rate    fmt_orig fmt_borodin         fmt
fmt_orig     207469/s          --        -57%        -83%
fmt_borodin  487805/s        135%          --        -60%
fmt         1219512/s        488%        150%          --

答案 2 :(得分:3)

“不,那些不是哈希。

[" bytes"=>0],[KB=>1],[MB=>2],[GB=>3]

根本不是哈希。 =>基本上只是一个逗号。所以这是

[" bytes", 0],["KB",1],["MB",2],["GB",3]

这是一种奇怪的方式,因为它有点构造哈希。

所以我写的更像是:

sub fmt2 {
   my ($bytes) = @_;
   my @units = qw ( bytes KB MB GB TB );
   #divide by 1024 whilst above
   while ( $bytes > 1024 ) {
      shift(@units); #drop one of the units prefixes until one 'fits'. 
      $bytes /= 1024;
   }
   return sprintf( '%.3g%s', $bytes, $units[0] );
}

答案 3 :(得分:1)

不,它没有传递哈希数组。它正在传递一个数组引用列表,其中每个引用的数组恰好包含两个元素。

Perl中的=>运算符也称为&#34; fat逗号&#34;运营商。它与,运算符相同,只是它会自动引用左手参数。它最常用于散列和散列引用,因为键通常是字符串,并且对于以某种方式链接键和值的可视指示很有用,但这不是必需的。

[" bytes"=>0],[KB=>1],[MB=>2],[GB=>3]

完全相同

[" bytes", 0],['KB', 1],['MB', 2],['GB', 3]

仅使用=>而不是,运算符不会将双元素数组转换为哈希值。如果您想传递map哈希引用列表,则必须将所有[ ]更改为{ }

{" bytes"=>0},{KB=>1},{MB=>2},{GB=>3}

More info on the fat comma operator

More info on Perl references

答案 4 :(得分:0)

map { sprintf '%.3g%s', $bytes/1024**$_->[1], $_->[0] } [" bytes"=>0],[KB=>1],[MB=>2],[GB=>3]

上面的部分返回一个用sprintf()格式化的字符串列表。

$_->[1]代表&#34;右边的数字。 bytes&#34;,KB,MB等,而$_->[0]代表&#34; bytes&#34;,KB,MB等字符串

整个函数返回在用sprintf()格式化的所有格式中具有最大长度的字符串。