“不能分配给不可变的值"尝试分配给字符串+角色时 [英] "Cannot assign to immutable value" when trying to assign to a string + role

查看:25
本文介绍了“不能分配给不可变的值"尝试分配给字符串+角色时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Iterable 文档页面中的示例开始

角色 DNA 做 Iterable {方法迭代器(){ self.comb.iterator }};我的@a 做 DNA = 'GAATCC';.say for @a;# 输出:«G␤A␤A␤T␤C␤C␤»

我发现它使用 @ 声明很奇怪,所以我将其更改为 natural 声明字符串的方式,$:

我的 $a 做 DNA = 'GAATCC';

但这失败了,因为不能分配给不可变的值"有点令人困惑.无需当场分配,我们可以这样做:

我的 $a = 'GAATCC';$a 做 DNA;.say for $a;

这只是将混合留到以后.但这只是打印字符串,没有注意 Iterable 混合.让我们明确地调用它:

.say for $a.iterator;

它和以前做的有点像,只是它打印了 $a.iterator 的值,而不实际调用函数:

<anon|69>.new

这看起来像 在另一个问题中发生的同样的事情.基线问题是我不明白 Iterable 的真正作用,以及 for 的真正作用以及它何时在某个对象上调用 iterator .有什么想法吗?

您的问题的标题指向一个错误.此答案涵盖了该错误以及您提出的其他隐式和显式问题.

背景

<块引用>

以有点令人困惑的无法分配给不可变的值"而失败.

我认为这是一个错误.让我们从一些有效的代码开始:

我的 $a = 42;说$a;#42说什么 $a;# (Int) 当前分配给 $a 的 VALUE 类型说什么 VAR $a;# (Scalar) 类型的 VARIABLE 当前绑定到 $a$a = 42;# 工作正常

my 声明中,$a 绑定到新的 标量容器.Scalar 容器通常会隐藏自己.如果你问 WHAT type $a 是什么,你实际上得到了当前分配给标量的值的类型(它包含"的值).您需要 VAR 来访问绑定到 $a 的 容器.当您使用 = 分配给 Scalar 容器时,您会将分配的值复制到容器中.

角色 foo {}$a 做 foo;# 将当前分配的 VALUE 更改为 $a# (不是绑定到 $a 的变量)说$a;# 42 混入 `foo` 的角色是不可见的说什么 $a;# (Int+{foo}) 当前分配给 $a 的 VALUE 类型说什么 VAR $a;# (Scalar) 类型的 VARIABLE 当前绑定到 $a$a = 99;说$a;#99

doesfoo 角色混合到 42 中.您仍然可以分配给 $a,因为它仍然绑定到 Scalar.

注意的这两种用法如何产生截然不同的效果:

我的 $a 做 foo;# 将 `foo` 混合到绑定到 $a 的 VARIABLE 中$a 做 foo;# 将 `foo` 混合到分配给 $a 的 VALUE 中

错误

$a.VAR 做 foo;# 将当前 BOUND 的 VARIABLE 更改为 $a(它会丢失 42)说$a;# Scalar+{foo}.new VALUE 当前分配给 $a说什么 $a;# (Scalar+{foo}) 当前分配给 $a 的 VALUE 类型说什么 VAR $a;# (Scalar+{foo}) 类型的 VARIABLE 当前绑定到 $a$a = '呃';# 不能赋值给不可变的值

doesfoo 角色混合到绑定到 $a 的 Scalar 中.似乎带有 mixin 的 Scalar 不再成功地用作容器并且分配失败.

目前在我看来这像是一个错误.

我的 $b 做 foo;# BINDS 混合在 VARIABLE 到 $b$b = '呃';# 不能赋值给不可变的值

my $b do foomy $b; 的结果相同;$b.VAR 做 foo; 所以你会遇到和上面一样的问题.

其他你感到困惑的事情

我的 $a = 'GAATCC';$a 做 DNA;.say for $a;

<块引用>

只打印字符串,不关注 Iterable mixin.

因为 $a VARIABLE 仍然绑定到 Scalar(如上面的 背景 部分所述),所以现在的 VALUE根据 for 使用的关于是否调用其参数的 .iterator 方法.

<块引用>

让我们显式调用它...打印 $a.iterator 的值,而不实际调用函数:

.say for $a.iterator;

它确实调用了您的 DNA 角色的 .iterator 方法.但这在 DNA 角色的 返回的 self.comb 末尾有 another .iterator 调用>iterator 方法,因此您正在 .say 执行辅助 .iterator.

当今有效的解决方案

我认为布拉德的回答很好地涵盖了您的大部分选择.

我认为你的 做 DNA如果您想使用 $ 印记, gist 与今天的 P6 一样好.

有一天可能会奏效的解决方案

在理想的世界中,P6 设计中的所有甜蜜都将在 6.c 和 Perl 6 的 Rakudo 编译器实现中完全实现.也许这将包括编写此代码并获得什么的能力你想要的:

class DNA is Scalar does Iterable { ... }我的 $a 是 DNA = 'GAATCC';.say for $a;

... 代码与 gist 中的代码大致相同,只是 DNA 类是标量容器,因此 >new 方法将改为 STORE 方法或类似的方法,将传递的值分配给 $!value 属性,或者在将值分配给使用 = 的容器.

但是,你会得到:

 是尚未实现的 $-sigil 变量的特征.对不起.

因此,您今天最接近 = 'string' 以更改 $a 的理想是使用 := DNA.new('string') 就像你在 gist 中所做的那样.

请注意,您可以将任意复合容器绑定到 @% sigil 变量.所以你可以看到事情最终应该如何运作.

Starting with the example in the Iterable doc page

role DNA does Iterable {
  method iterator(){ self.comb.iterator }
};

my @a does DNA = 'GAATCC';
.say for @a; # OUTPUT: «G␤A␤A␤T␤C␤C␤» 

I found it weird it's declared using the @, so I changed it to the natural way of declaring strings, $:

my $a does DNA = 'GAATCC';

But that fails with a somewhat bewildering "Cannot assign to an immutable value". No need to assign on the spot, so we can do:

my $a = 'GAATCC';
$a does DNA;
.say for $a;

Which just leaves mixing-in for later. But that just prints the string, without paying any attention to the Iterable mixin. Let's call it then explicitly:

.say for $a.iterator;

it does kinda the same thing as before, only it prints the value of $a.iterator, without actually calling the function:

<anon|69>.new

This looks like the same thing it's going on in this other question. Baseline question is I don't understand what role Iterable really does, and what for really does and when it is calling iterator on some object. Any idea?

解决方案

Your question's title points to a bug. This answer covers the bug and also other implicit and explicit questions you asked.

Background

fails with a somewhat bewildering "Cannot assign to an immutable value".

I think that's a bug. Let's start with some code that works:

my $a = 42;
say $a;          # 42
say WHAT $a;     # (Int)               type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar)            type of VARIABLE currently BOUND to $a
$a = 42;         # works fine

In the my declaraton $a gets BOUND to a new Scalar container. A Scalar container normally hides itself. If you ask WHAT type $a is, you actually get the type of the value currently ASSIGNED to the Scalar (the value it "contains"). You need VAR to access the container BOUND to $a. When you assign with = to a Scalar container you copy the assigned value into the container.

role foo {}
$a does foo;     # changes the VALUE currently ASSIGNED to $a
                 # (NOT the VARIABLE that is BOUND to $a)
say $a;          # 42                  mixed in `foo` role is invisible
say WHAT $a;     # (Int+{foo})         type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar)            type of VARIABLE currently BOUND to $a
$a = 99; say $a; # 99

The does mixes the foo role into the 42. You can still assign to $a because it's still bound to a Scalar.

Note how these two uses of does have very different effects:

my $a does foo;  # mixes `foo` into VARIABLE bound to $a
$a does foo;     # mixes `foo` into VALUE assigned to $a

The bug

$a.VAR does foo; # changes VARIABLE currently BOUND to $a (and it loses the 42)
say $a;          # Scalar+{foo}.new    VALUE currently ASSIGNED to $a
say WHAT $a;     # (Scalar+{foo})      type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar+{foo})      type of VARIABLE currently BOUND to $a

$a = 'uhoh';     # Cannot assign to an immutable value

The does mixes the foo role into the Scalar bound to $a. It seems that a Scalar with a mixin no longer successfully functions as a container and the assignment fails.

This currently looks to me like a bug.

my $b does foo;  # BINDS mixed in VARIABLE to $b
$b = 'uhoh';     # Cannot assign to an immutable value

my $b does foo has the same result as my $b; $b.VAR does foo; so you get the same problem as above.

Other things you were confused about

my $a = 'GAATCC';
$a does DNA;
.say for $a;

just prints the string, without paying any attention to the Iterable mixin.

Because the $a VARIABLE is still bound to a Scalar (as explained in the Background section above), the VALUE that now has a DNA role mixed in is irrelevant per the decision process for uses about whether to call its argument's .iterator method.

Let's call it then explicitly ... prints the value of $a.iterator, without actually calling the function:

.say for $a.iterator;

Well it does call your DNA role's .iterator method. But that has another .iterator call at the end of the self.comb returned by your DNA role's iterator method so you're .saying that secondary .iterator.

Solutions that work today

I think Brad's answer nicely covers most of your options.

And I think your nice does DNA gist is as good as it gets with today's P6 if you want to use the $ sigil.

A solution that might one day work

In an ideal world all the sweetness in the P6 design would be fully realized in 6.c and the Rakudo compiler implementation of Perl 6. Perhaps that would include the ability to write this and get what you want:

class DNA is Scalar does Iterable { ... }
my $a is DNA = 'GAATCC';
.say for $a;

The ... code would be about the same as what you have in your gist except that the DNA class would be a scalar container, and so the new method would instead be a STORE method or similar that would assign the passed value to a $!value attribute or some such when a value was assigned to the container using =.

But instead, you get:

is trait on $-sigil variable not yet implemented. Sorry.

So the closest you can get today to the ideal of = 'string' to change $a is to bind using := DNA.new('string') as you did in your gist.

Note that you can bind arbitrary composite containers to @ and % sigil variables. So you can see how things are supposed to eventually work.

这篇关于“不能分配给不可变的值"尝试分配给字符串+角色时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆