Nano Hash - криптовалюты, майнинг, программирование

Странности, связанные с перегрузкой Perl

Короче говоря: мы хотим пометить строки, чтобы позже мы могли что-то с ними делать, даже если они будут встроены в другие строки.

Итак, мы решили, эй, давайте попробуем перегрузить. Это довольно аккуратно. Я могу сделать что-то вроде:

my $str = str::new('<encode this later>');
my $html = "<html>$str</html>";
print $html; # <html><encode this later></html>
print $html->encode; # <html>&lt;encode this later&gt;</html>

Он делает это путем перегрузки оператора конкатенации для создания нового массива объектов с простой строкой «‹html>», оболочкой объекта «‹encode this Later>» и простой строкой «‹/html>». Он может вкладывать их произвольно. При кодировании он оставит простые строки, но закодирует строки объекта. Но если вы преобразуете объект в строку, он просто выдает все это в виде простых строк.

Это работает хорошо, за исключением того, что в некоторых случаях это приводит к искажению без видимой причины. В приведенном ниже сценарии показано поведение, которое я продублировал в версиях с 5.10 по 5.22.

#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper; $Data::Dumper::Sortkeys=1;

my $str1 = str::new('foo');
my $str2 = str::new('bar');

my $good1 = "$str1 $str2";
my $good2;
$good2 = $good1;
my($good3, $good4);
$good3 = "$str1 a";
$good4 = "a $str1";

my($bad1, $bad2, $bad3);
$bad1 = "a $str1 a";
$bad2 = "$str1 $str2";
$bad3 = "a $str1 a $str2 a";

say Dumper { GOOD => [$good1, $good2, $good3], BAD => [$bad1, $bad2, $bad3] };

$bad1 = ''."a $str1 a";
$bad2 = ''."$str1 $str2";
$bad3 = ''."a $str1 a $str2 a";
say Dumper { BAD_GOOD => [$bad1, $bad2, $bad3] };


package str;
use Data::Dumper; $Data::Dumper::Sortkeys=1;

use strict;
use warnings;
use 5.010;

use Scalar::Util 'reftype';

use overload (
    '""'        => \&stringify,
    '.'         => \&concat,
);

sub new {
    my($value) = @_;
    bless((ref $value ? $value : \$value), __PACKAGE__);
} 

sub stringify {
    my($str) = @_;
    #say Dumper { stringify => \@_ };
    if (reftype($str) eq 'ARRAY') {
        return join '', @$str;
    }
    else {
        $$str;
    }
}

sub concat {
    my($s1, $s2, $inverted) = @_;
    #say Dumper { concat => \@_ };
    return new( $inverted ? [$s2, $s1] : [$s1, $s2] );
}

1;

Я хочу, чтобы все они выводились как объекты, а не строки. Но все «ПЛОХИЕ» примеры зашифрованы. Все "ПЛОХИЕ" примеры - это когда я присваиваю строковый объект, который я в данный момент объединяю с ранее объявленной переменной. Если я объявляю в то же время или объединяю строки ранее, или добавляю дополнительную конкатенацию (помимо интерполированной строки concat), то это работает нормально.

Это безумие.

Результат скрипта:

$VAR1 = {
    'BAD' => [
        'a foo a',
        'foo bar',
        'a foo a bar a'
    ],
    'GOOD' => [
        bless( [
            bless( [
                bless( do{\(my $o = 'foo')}, 'str' ),
                ' '
            ], 'str' ),
            bless( do{\(my $o = 'bar')}, 'str' )
        ], 'str' ),
        $VAR1->{'GOOD'}[0],
        bless( [
            $VAR1->{'GOOD'}[0][0][0],
            ' a'
        ], 'str' )
    ]
};

$VAR1 = {
    'BAD_GOOD' => [
        bless( [
            '',
            bless( [
                bless( [
                    'a ',
                    bless( do{\(my $o = 'foo')}, 'str' )
                ], 'str' ),
                ' a'
            ], 'str' )
        ], 'str' ),
        bless( [
            '',
            bless( [
                bless( [
                    $VAR1->{'BAD_GOOD'}[0][1][0][1],
                    ' '
                ], 'str' ),
                bless( do{\(my $o = 'bar')}, 'str' )
            ], 'str' )
        ], 'str' ),
        bless( [
            '',
            bless( [
                bless( [
                    bless( [
                        bless( [
                            'a ',
                            $VAR1->{'BAD_GOOD'}[0][1][0][1]
                        ], 'str' ),
                        ' a '
                    ], 'str' ),
                    $VAR1->{'BAD_GOOD'}[1][1][1]
                ], 'str' ),
                ' a'
            ], 'str' )
        ], 'str' )
    ]
};

Поведение не имеет для меня никакого смысла. Я хотел бы понять, почему это работает таким образом, и я хотел бы найти обходной путь.


  • потенциальный обходной путь: p3rl.org/Variable::Magic 23.06.2018
  • Отправлено на PerlMonks, где я написал ответ (потому что первым увидел его там). 23.06.2018
  • @daxim Я не думаю, что это помогает, так как я проигрываю задание, а магия теряется при задании. Не уверен, как я мог использовать это здесь. По сути, я хочу контролировать, когда происходит стрингификация, но не похоже, что я могу это сделать. 23.06.2018
  • Совет: sub new { my($value) = @_; bless((ref $value ? $value : \$value), __PACKAGE__); } должно быть sub new { my($class, $value) = @_; bless((ref $value ? $value : \$value)), $class); } , а str::new('foo') должно быть str->new('foo'). 23.06.2018
  • Я рекомендую вам использовать инструмент командной строки perlbug, чтобы попросить p5p объяснить результат это очищенная версия вашей программы. Включите вывод. 24.06.2018
  • @ysth, см. RT # 132793. Commit 55b62dee2d8dffa7b36b3b613ee4727fbefdb9e3 просто восстанавливает существующие ошибки5 и более ранние версии. поведение. 30.06.2018
  • @ikegami спасибо, я думаю, это поможет исправить ошибку / несоответствие perl. хотя это не совсем соответствует тому, что я вижу. 30.06.2018
  • @ysth, дело в том, что это известная ошибка, хотя для нее может не быть билета. 30.06.2018

Ответы:


1

Что ж, это не самое лучшее решение, и оно не отвечает, почему Perl делает это, но у меня есть кое-что... Я оставил там несколько отладочных операторов печати.

По какой-то причине Perl считает, что вы хотите преобразовать скалярную ссылку на ваш объект в скалярную строку. Вы можете заставить его не делать этого, добавив ссылку на ссылку, а затем разыменовав ее.

#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper; $Data::Dumper::Sortkeys=1;
use Scalar::Util 'reftype';

my $str1 = str::new('foo');
my $str2 = str::new('bar');

say 'good1';
my $good1 = "$str1 $str2";
say 'g1 ', reftype($good1);
say Dumper $good1;

say 'bad1';
my $bad1;
say 'b1 ', reftype($bad1);
$bad1 = "$str1 $str2";
say 'b2 ', reftype($bad1);
say Dumper $bad1;

say 'workaround';
my $workaround;
say 'w1 ', reftype($workaround);
$workaround = ${\"$str1 $str2"};
say 'w2 ', reftype($workaround);
say Dumper $workaround;


package str;
use Data::Dumper; $Data::Dumper::Sortkeys=1;

use strict;
use warnings;
use 5.010;

use Scalar::Util 'reftype';

use overload (
    '""'        => \&stringify,
    '.'         => \&concat,
);

sub new {
    my ($value) = @_;
    bless((ref $value ? $value : \$value), __PACKAGE__);
} 

sub stringify {
    my ($str) = @_;

    say "stringify";
    say reftype($str);

    if (reftype($str) eq 'ARRAY') {
        say scalar @$str;
        return join '', @$str;
    }
    else {
        $$str;
    }
}

sub concat {
    my ($s1, $s2, $inverted) = @_;

    say "concat";
    say reftype($s1);
    say reftype($s2);
    say reftype($inverted);

    return new( $inverted ? [$s2, $s1] : [$s1, $s2] );
}

1;

$обходной путь дает вам следующее

$VAR1 = bless( [
                 bless( [
                          bless( do{\(my $o = 'foo')}, 'str' ),
                          ' '
                        ], 'str' ),
                 bless( do{\(my $o = 'bar')}, 'str' )
               ], 'str' );
17.08.2018
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..