Ruby的%格式化操作符允许使用散列来替换模板值:
"%{a}" % { a: "banana" } # => "banana"然而,这不适用于动态哈希:
"%{a}" % Hash.new { |hash, key| hash[key] = "banana" } # => KeyError有什么解决方法吗?
编辑:X到这个Y是从每个键的可能值的数组中创建一个格式散列。我目前的解决方案是这样的:
content = Hash[CONTENT.map { |k, v| [k, v.sample] }]然而,我认为这相当丑陋,作为一个动态解决方案会更好。
发布于 2015-08-10 10:09:50
我认为你不能随心所欲,至少用核磁共振是不行的。
如果您仔细查看代码,就会发现sprintf.c中的String#%最终是用C实现的。C实现does this的%{x}处理部分
if (sym != Qnil) nextvalue = rb_hash_lookup2(hash, sym, Qundef);
if (nextvalue == Qundef) {
rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, start);
}rb_hash_lookup2调用用于从hash获取sym键的值,如果rb_hash_lookup2未找到任何内容(即rb_hash_lookup2返回Qundef),则会引发KeyError。现在,如果我们看一下rb_hash_lookup2,我们会发现它显式地没有使用哈希默认值:
VALUE
rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
{
st_data_t val;
if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
return def; /* without Hash#default */
}
return (VALUE)val;
}请注意,如果找不到键,它将使用def参数,而不是散列的默认值:
return def; /* without Hash#default */如果您查看Hash#[] implementation,您会发现它与rb_hash_lookup2之间唯一的区别是return def;被替换为:
return hash_default_value(hash, key);这就是你的问题:String#%显式地绕过了你的哈希默认值逻辑。由于所有这些都是通过直接C调用实现的,所以您无法获取猴子补丁Hash#[]、Hash#fetch、Hash#has_key?或其他任何内容;类似地,您甚至不能子类Hash并覆盖任何方法来绕过String#%的脑损伤。
我认为你的丑陋的解决方案比其他的解决方案(重新实现String#%,修改一堆正则表达式,等等)要好一些。
YMMV,当然还有其他Ruby实现。
发布于 2015-08-10 10:16:32
您可以使用Hash#values_at显式初始化字符串的键,但这是一种技巧:
"%{a}, %{b}" % Hash.new {|h, k| h[k] = "banana" }.tap {|h| h.values_at(:a, :b) }https://stackoverflow.com/questions/31910205
复制相似问题