【发布时间】:2012-06-01 00:19:18
【问题描述】:
如何将函数参数列表规范化为字符串,以便两个参数列表转换为相同的字符串,如果它们实际上是等效的?算法应该
- 深入比较嵌入式哈希和列表,而不是通过引用来比较
- 忽略哈希键顺序
- 忽略 3 和“3”之间的区别
- 生成一个相对易读的字符串(不是必需的,但很好用于调试)
- 表现良好(XS 优于 Perl)
这对于memoization 是必要的,即根据函数的参数缓存函数的结果。
作为一个稻草人示例,Memoize 将其用作默认规范化器,但 #1 和 #3 失败:
$argstr = join chr(28),@_;
有一段时间我的首选规范化器是
JSON::XS->new->utf8->canonical
但是,它会根据最近使用标量的方式来处理数字 3 和字符串“3”differently。这可以为本质上等效的参数列表生成不同的字符串,并降低记忆的好处。 (绝大多数函数不会知道或关心它们是否得到 3 或“3”。)
为了好玩,我查看了一堆序列化程序,看看哪些区分 3 和“3”:
Data::Dump : equal - [3] vs [3]
Data::Dumper : not equal - [3] vs ['3']
FreezeThaw : equal - FrT;@1|@1|$1|3 vs FrT;@1|@1|$1|3
JSON::PP : not equal - [3] vs ["3"]
JSON::XS : not equal - [3] vs ["3"]
Storable : not equal - <unprintable>
YAML : equal - ---\n- 3\n vs ---\n- 3\n
YAML::Syck : equal - --- \n- 3\n vs --- \n- 3\n
YAML::XS : not equal - ---\n- 3\n vs ---\n- '3'\n
在报告“相等”的那些中,不确定如何让他们忽略散列键顺序。
我可以事先遍历参数列表并将所有数字字符串化,但这需要进行深层复制并且会违反#5。
谢谢!
【问题讨论】:
-
还有Test::More的is_deeply和Test::Deep的eq_deeply。
标签: perl