Строки Perl являются изменяемыми, поэтому добавление к строке НЕ влечет за собой штраф за дублирование строки.
Вы можете попробовать все, что хотите, чтобы найти «более быстрый» способ, но это пахнет преждевременной оптимизацией.
Например, я собрал класс, который отвлекся от тяжелой работы. Он работает отлично, но, несмотря на все свои глупые трюки, очень медленно.
Вот результат:
Rate magic normal
magic 1.72/s -- -93%
normal 23.9/s 1289% --
Да, все верно, Perl на 1200% быстрее, чем я думал, что это респектабельная реализация.
Профилируйте свой код и найдите реальные проблемы, не пытайтесь оптимизировать то, что даже не является известной проблемой.
#!/usr/bin/perl
use strict;
use warnings;
{
package MagicString;
use Moose;
has _buffer => (
isa => 'Str',
is => 'rw',
);
has _buffer_size => (
isa => 'Int',
is => 'rw',
default => 0,
);
has step_size => (
isa => 'Int',
is => 'rw',
default => 32768,
);
has _tail_pos => (
isa => 'Int',
is => 'rw',
default => 0,
);
sub BUILD {
my $self = shift;
$self->_buffer( chr(0) x $self->step_size );
}
sub value {
my $self = shift;
return substr( $self->{buffer}, 0, $self->{_tail_pos} );
}
sub append {
my $self = shift;
my $value = shift;
my $L = length($value);
if ( ( $self->{_tail_pos} + $L ) > $self->{_buffer_size } ){
$self->{buffer} .= (chr(0) x $self->{step_size} );
$self->{_buffer_size} += $self->{step_size};
}
substr( $self->{buffer}, $self->{_tail_pos}, $L, $value );
$self->{_tail_pos} += $L;
}
__PACKAGE__->meta->make_immutable;
}
use Benchmark qw( :all :hireswallclock );
cmpthese( -10 , {
magic => sub{
my $x = MagicString->new();
for ( 1 .. 200001 ){
$x->append( "hello");
}
my $y = $x->value();
},
normal =>sub{
my $x = '';
for ( 1 .. 200001 ){
$x .= 'hello';
}
my $y = $x;
}
});
#use Data::Dumper;
#print Dumper( length( $x->value() ));