gpt4 book ai didi

hash - 创建一个在模块外部只读但在内部读/写的哈希

转载 作者:行者123 更新时间:2023-12-04 06:14:22 25 4
gpt4 key购买 nike

我正在创建一个具有一些相当重的嵌套哈希的模块。哈希需要由模块半定期修改,不幸的是排除了使用 Map .

通常,嵌套散列的一个分支将返回给模块 [1] 的用户,最简单的事情就是返回该嵌套散列,例如:

return %data{$branch}{$subbranch} 
# ↪︎ %(subsubbranch1 => ... , subsubbranch2 => ... )

但是,像数组或散列这样的容器的本质是,虽然您可以将它们设为只读,但仍然可以修改键/值。尽管出于多种原因,模块用户实际上不应修改这些值。强制转换为 Map不会有帮助,因为如果任何值也是容器,它们也将是可修改的。

我的第一个想法是子类 Hash (或以其他方式自定义 Associative ),但默认情况下自动生存仍会使用 Hash。然而,这可以通过覆盖 AT-KEY 来轻松解决。和 ASSIGN-KEY使 AT-KEY如果键不存在,则返回子类的实例:
class ProtectedHash is Hash {
has %!hash = ();
method EXISTS-KEY ($key) { %!hash{$key}:exists }
method ASSIGN-KEY ($key, \value) { %!hash{$key} = value }
method AT-KEY ($key) {
%!hash{$key} := ProtectedHash.new unless %!hash{$key}:exists;
%!hash{$key};
}
}

如果 ASSIGN-KEY,我想做的是失败。 (或 AT-KEY 的自动生存部分)是从我的模块外部调用的。我考虑过使用类似 $?MODULE 的东西,但这将在编译时设置并且总是正确的。看起来我可以稍微调整一下 Backtrace 并检查调用的文件的名称,但是我可以假设这两个函数的调用跟踪有多一致?

例如,对于 ASSIGN-KEY我有:
method ASSIGN-KEY ($key, \value) { 
my @trace = Backtrace.new.list[3..*];
# The first three can be ignored:
# 0: code at ...Backtrace.pm6
# 1: method new at ...Backtrace.pm6
# 2: method AT-KEY at ...ThisFile.pm6
if/unless ??? {
%!hash{$key} = value
}
}
AT-KEY通常由子 postcircumfix<{ }> 调用(在这种情况下 @trace[0] 可以忽略,而 trace[1] 将是感兴趣的)但也可以直接调用,尽管很少,在这种情况下 trace[0]是我要验证文件名的地方。
AT-KEY还有其他常用的方法吗?或 ASSIGN-KEY可能被称为?还是应该检查这两个步骤占对这些方法的调用的 99.9%? [2]

[1] 用户可能想要操作的只有少数 subx4 分支,因此我认为最好为它们提供必然较慢的 .Hash当他们真正需要它而不是假设他们总是需要一个可操作的容器时的方法。有时,这些调用可能足够多(特别是通过 get-branch($foo){$subbranch}{$subsubbranch} 模式),以至于创建哈希深度克隆的额外开销变得相当重要。
[2] 我不太担心阻止任何访问(尽管我当然很好奇这是否可能纯粹通过子类化),因为我确信一个相当勤奋的编码人员总能找到一些东西,但我想捕获最常见的那些作为说“不能碰这个!”的一种方式。 (提示 90 年代的音乐……)并提供 Awesome错误信息。

最佳答案

通过返回包装原始 Array 的内容可能更容易实现此目的。或 Hash ,或者使用 but做一个浅拷贝并混入其中(这意味着您保留原始类型)。

我们可以像这样声明一个角色:

role Can'tTouchThis {
method AT-KEY(|) {
untouchable callsame
}

method ASSIGN-KEY(|) {
die "Cannot assign to this";
}

method AT-POS(|) {
untouchable callsame
}

method ASSIGN-POS(|) {
die "Cannot assign to this";
}
}
sub untouchable定义为:
multi untouchable(Positional \p) {
p but Can'tTouchThis
}
multi untouchable(Associative \a) {
a but Can'tTouchThis
}
multi untouchable(\o) {
o
}

因此,通过在访问时处理嵌套数据结构,也为这些数据结构创建一个只读外观。

下面是一个例子和一些测试用例来说明效果:
class Example {
has %!foo = a => [ 1, 2, [ 3, 4] ], b => { c => { d => 42, e => 19 }, f => 100 };

method get($sym) {
untouchable %!foo{$sym}
}
}

given Example.new {
use Test;

# Positional cases
is .get('a')[0], 1;
is .get('a')[2][1], 4;
dies-ok { .get('a')[1] = 42 };
is .get('a')[1], 2;

# Associative cases
is .get('b')<c><d>, 42;
dies-ok { .get('b')<f> = 99 };
dies-ok { .get('b')<c><d> = 99 };
is .get('b')<f>, 100;
is .get('b')<c><d>, 42;

# Auto-viv also doesn't work
dies-ok { .get('a')[4]<a> = 99 };
dies-ok { .get('a')[4][0] = 99 };
}

删除 untouchable调用 get方法来查看这里的大多数测试由于缺乏保护而失败。

关于hash - 创建一个在模块外部只读但在内部读/写的哈希,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55841159/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com