`state` 和 `const` 有什么区别?

What is the difference between `state` and `const`?

好像是这样写的:

use Const::Fast;
const $xx, 77;
sub test {
    do_something_with( $xx );    
}

sub test {
    state $xx =  77;
    do_something_with( $xx );    
}

完成此操作的更好方法是什么:通过 const 还是通过 state

sub get_ip_country {
    my ($ip_address) = @_;
    my $ip_cc_database = GeoIP2::Database::Reader->new(file => '/etc/project/GeoLite2-Country.mmdb');
    ...
}

UPD
在这个 sub 中,我没有更改指向 geoip 数据库的指针,因此它应该是 const。但是我不想每次调用 sub 时都重新创建对象(这很慢)。所以我想使用 state 会更快,尽管指针没有改变。

好像应该是const state $ip_cc_database

他们不做同样的事情。

  • state 声明了一个变量,该变量只会在您第一次进入该函数时被初始化。虽然它是可变的,所以你可以改变它的值,但它会在调用同一个函数之间保持值。例如,该程序将打印 7879
    sub test {
        state $xx = 77;     # initialization only happens once
        print ++$xx . "\n"; # step the current value and print it
    }
    test; # 78
    test; # 79
    
  • const 声明一个不可变(只读)变量,如果在函数中声明,每次调用该函数时都会重新初始化。

如果你想要一个恒定的值,那么你应该使用像 Const::Fast.

这样的东西

但是如果您想要一个可以更改的值,但在函数调用之间保留其值,那么您需要 state variable.

所以运行,这个:

sub test {
  state $x = 1;

  say $x++;
}

test() for 1 .. 10;

给出这个:

1
2
3
4
5
6
7
8
9
10

但是运行这个:

use Const::Fast;

sub test {
  const my $x, 1;

  say $x++;
}

test() for 1 .. 10;

给出运行时错误:

Modification of a read-only value attempted at const_test line 12.

正如@TedLyngmo 在对您的 OP 的评论中指出的那样,const state 不是有效的 Perl。 const 是一个 pragma,因此在编译时工作,而 state 是一个运行时构造。

就您的效率要求而言,GeoIP2::Database::Reader 构造函数只调用一次,两者都可以。如果您进一步希望它是 read-only 以便您不会无意中使引用无效,您仍然可以同时使用两者。 const 会自动为您完成,但您可以使用 state 和间接层复制该行为:

sub ip_cc_database {
   state $db = GeoIP2::Database::Reader->new(file => '/etc/project/GeoLite2-Country.mmdb');
}
sub get_ip_country {
    my ($ip_address) = @_;
    my $ip_cc_database = ip_cc_database();
    ...
}

关于何时使用一个而不是另一个的问题的答案有点微妙。

这两种方法的真正区别在于调用构造函数的时间。使用 const 它是在编译阶段,使用 state 它是在运行时。

如果您的应用程序 总是 调用 get_ip_country,并且您不关心在进程的生命周期内分摊启动成本,const更简单。

但是,如果您不总是调用 get_ip_country,并且创建 GeoIP2::Database::Reader 对象的成本很高,那么使用 state 意味着您只需在需要时支付该费用.

还需要考虑用户体验。如果您的程序是交互式的,或者如果它在您需要调用 get_ip_country 之前就开始生成输出,则延迟创建对象直到实际需要它意味着您的程序不会只是坐在那里似乎什么都不做,直到所有启动完成。