Versão Rakudo 2020.01
Eu estava escrevendo um código descartável e não me incomodei em implementar uma classe, apenas usei um Hash como trabalho. Eu encontrei um comportamento surpreendente com listas.
class Q1 {}
class R1 {
has Str $.some-str is required;
has @.some-list is required;
}
my $r1 = R1.new(
some-str => '…',
some-list => (Q1.new, Q1.new, Q1.new)
);
# hash as poor man's class
my $r2 = {
some-str => '…',
some-list => (Q1.new, Q1.new, Q1.new)
};
multi sub frob(R1 $r1) {
for #`(Array) $r1.some-list -> $elem {
$elem.raku.say;
}
}
multi sub frob(Hash $r2) {
for #`(List) $r2<some-list> -> $elem {
$elem.raku.say;
}
}
frob $r1;
# OK.
# Q1.new
# Q1.new
# Q1.new
frob $r2;
# got:
# (Q1.new, Q1.new, Q1.new)
# expected:
# Q1.new
# Q1.new
# Q1.new
frob(Hash …)
funciona como esperado quando ligo .flat
ou .list
na lista (mesmo que já seja uma lista‽).
Tentei criar um caso de teste mínimo, mas isso funciona com o AFAICT idêntico.
for [Q1.new, Q1.new, Q1.new] -> $elem {
$elem.raku.say;
}
for (Q1.new, Q1.new, Q1.new) -> $elem {
$elem.raku.say;
}
Eu li a documentação em List e Scalar várias vezes, mas ainda não consigo entender minha observação. Por que preciso tratar a lista no Hash, mas não na classe?
No such method 'raku' for invocant of type 'Q1'
quando tento executar isso.perl
: talvez o seu Rakudo não seja atual o suficiente?Respostas:
for
não faz loop sobre valores discriminados.Quando você coloca algo em um contêiner escalar, ele é discriminado.
Um elemento em um Hash também é um contêiner escalar.
Portanto, se você colocar uma lista em um Hash, ele será detalhado.
Portanto, se você quiser fazer um loop sobre os valores, precisará removê-lo.
Você pode evitar esse contêiner escalar vinculando.
(Isso impede que o
=
operador trabalhe nesse elemento hash.)Se você notou que no objeto de classe você o definiu com um
@
não$
Se você o mudou para um
$
e o marcou,rw
ele funcionará como o exemplo HashTem que ser uma
$
variável ou não estará em um contêiner Scalar.Ele também deve ser marcado
rw
para que o acessador retorne o contêiner escalar real, em vez do valor não discriminado.fonte
Isso não tem nada a ver com
[]
versus()
. Isso tem a ver com a diferença entre$
(indicando um item) e%
(indicando um associativo):No caso "b", o que é recebido é um item . Se você tentar repetir isso, receberá 1 iteração para esse item. Enquanto no caso "a", você indicou que é algo associativo que você deseja (com o
%
sigilo).Talvez um exemplo mais claro:
Como
$a
é um item, você obtém uma iteração. Você pode indicar que deseja iterar na coisa subjacente, adicionando.list
:Ou, se você quiser obter mais linenoisy, prefixe a
@
:fonte
Não estritamente uma resposta, mas uma observação: em Raku, vale a pena usar classes em vez de hashes, ao contrário de Perl:
Usando classes e objetos:
O uso de classes não só é mais rápido, como também impede que você cometa erros de digitação na inicialização, se você adicionar a
is required
característica:E impede que você faça erros de digitação ao acessá-lo:
fonte
FALLBACK
)