C++ 能否成为你新的脚本语言?(2)

#!/usr/bin/env perl
 
use strict;
use warnings;
 
run(\@ARGV);
 
sub run {
    my $argv = shift;
    my @counts;
 
    for my $file ( @$argv ) {
        my $count = -1;
        eval {
            $count = word_count($file);
            1;
        } or warn "$@";
 
        push @counts, {
            file => $file,
            word_count => $count,
        };
    }
 
    for my $result (@counts) {
        printf "%s: %d words\n", $result->{file}, $result->{word_count};
    }
}
 
sub word_count {
    my $file = shift;
    my %words;
 
    open my $fh, '<', $file
        or die "Cannot open '$file': $!";
 
    while (my $line = <$fh>) {
        my @words = split ' ', $line;
        $words{ $_ } += 1 for @words;
    }
 
    close $fh;
 
    my $word_count;
    $word_count += $_ for values %words;
    return $word_count;
}

而且,这是我最大的付出在转化 Perl 到现代风格的 C++ 上面。我没有尝试写特别搞笑的代码:只是和 Perl 一样,我把重点放在写代码上面,使得我感到非常自然,同时确保两个程序都做大致相同的事情。

#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <numeric>
#include <unordered_map>
#include <string>
#include <vector>
 
using std::accumulate;
using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::make_pair;
using std::pair;
using std::strerror;
using std::string;
using std::unordered_map;
using std::vector;
 
int word_count(const char *const file) noexcept(false);
 
int main(int argc, char *argv[]) {
    vector< pair<string, int> > counts {};
 
    for (auto i = 1; i < argc; i += 1) {
        try {
            counts.push_back(make_pair(argv[i], word_count(argv[i])));
        } catch (const string& e) {
            cerr << e << endl;
            counts.push_back(make_pair(argv[i], -1));
        }
    }
 
    for (auto& result : counts) {
        cout << result.first << ": " << result.second << " words" << endl;
    }
 
    return 0;
}
 
int
word_count(const char *const file) noexcept(false) {
    errno = 0;
    ifstream fp(file);
    {
        // Does fp.fail() preserve errno?
        int save_errno = errno;
        if (fp.fail()) {
            throw("Cannot open '" + string(file) + "': " + strerror(save_errno));
        }
    }
 
    unordered_map<string, int> word_count {};
    string word;
 
    while (fp >> word) {
        word_count[word] += 1;
    }
 
    fp.close();
 
    return accumulate(
        word_count.cbegin(),
        word_count.cend(),
        0,
        [](int sum, auto& el) { return sum += el.second; }
    );
}

20 行代码用于 #include 和 using 声明可能看起来有点多,但是我抬眼 using namespace std,也讨厌不断地输入 std::... 更多的是因为我喜欢较短的代码行。

首先要注意的是没有看得见的显式的内存分配。容器集装箱管理自己的内存。

第二,这是一个大问题:我们有自动导入(autovivification)!

unordered_map<string, int> word_count {};
string word;
 
while (fp >> word) {
    word_count[word] += 1;
}
 

第三,我们有 lambda 表达式:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/2f6b3136625d6c2e6dc52ab9b345a7e1.html