考虑以下代码:
import ballerina/io;
type User record {|
string name;
string email;
|};
const USER = {
name: "John Doe",
email: "[email protected]"
};
public function main() {
User user = USER.clone();
user.name = "Jane Doe";
io:println("User name: " + user.name);
}
这段代码正确吗?我有一张常量地图,并将其克隆为用户并更新了一个字段。由于它是具有常量映射的克隆,因此字段是否克隆为只读?那么 clone() 应该返回编译器错误,因为在目标类型中,该字段不是显式只读的,对吗?
目前由于此运行时错误而失败:
error: {ballerina/lang.map}InherentTypeViolation {"message":"cannot update 'readonly' field 'name' in record of type '(service:record {| "John Doe" name; "[email protected]" email; |} & readonly)'"}
But if I use cloneWithType() it is working fine:
public function main() returns error? {
User user = check USER.cloneWithType();
user.name = "Jane Doe";
io:println("User name: " + user.name);
}
有人可以解释一下这里的行为吗?
这里 USER 的类型被推断为
{
name: "John Doe",
email: "[email protected]"
} & readonly
由 Ballerina 编译器生成。
USER.clone() 将返回类型为 的克隆记录
{
name: "John Doe",
email: "[email protected]"
} & readonly
(原值的类型)
该类型是 User 的子类型。因此编译器允许将其分配给用户变量。但克隆值是只读的。因为记录的原始类型是readonly 所以我们无法更新记录的字段。这就是错误消息的含义。
示例:- 假设有一种类型称为 A。
A & readonly a = value
A b = a
这里 b 的类型是 A & readonly 所以我们无法更新值 b 中的字段
但是如果你使用 CloneWithType 函数,它会克隆该值并将其转换为预期的类型。
所以这里用户的类型是User。
User user = check USER.cloneWithType();
所以我们可以更新这里的字段。
顺便说一句,重要的是要知道,当您使用带有不可变值的clone()(或cloneReadOnly())时,不会创建副本。值本身就是结果。
User user = USER.clone();
io:println(user == USER); // true
User & readonly userImmutable = USER.cloneReadOnly();
io:println(userImmutable == USER); // true