2011-03-31 96 views
7

我在rosettacode.org上发布了以下代码,用于converting Arabic and Roman numerals的任务。D2:std.algorithm.indexOf不再工作

import std.regex, std.array, std.algorithm; 

immutable { 
    int[] weights = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]; 
    string[] symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", 
         "V", "IV", "I"]; 
} 

string toRoman(int n) { 
    auto app = appender!string; 
    foreach (i, w; weights) { 
     while (n >= w) { 
      app.put(symbols[i]); 
      n -= w; 
     } 
     if (n == 0) break; 
    } 
    return app.data; 
} 

int toArabic(string s) { 
    int arabic; 
    foreach (m; match(s, "CM|CD|XC|XL|IX|IV|[MDCLXVI]")) { 
     arabic += weights[symbols.indexOf(m.hit)]; 
    } 
    return arabic; 
} 

它曾经工作得很好,但现在我得到一个编译器错误。

Error: template std.algorithm.indexOf(alias pred = "a == b",R1,R2) if (is(typeof(startsWith!(pred)(haystack,needl e)))) does not match any function template declaration

根据文档indexOf已弃用,应使用countUntil替代,但它给了我同样的错误。

回答

6

长的故事,但我会尽量保持简短:

std.algorithm.indexOf预计的input range,这是一个structural type必须定义frontpopFront()empty。对于数组,这些方法是defined in std.array,并且通过统一函数调用语法工作,这允许fun(someArray)someArray.fun()一样工作。

immutable string[]不是输入范围,因为popFront删除了数组的第一个元素,这对于一个不可变类型是无法完成的。这曾经工作的事实是一个错误。

我已更新Rosetta代码条目,将symbols更改为immutable(string)[]。在这里,symbols的元素是不可变的,但是数组可能被切片并重新分配。例如:

void main() { 
    immutable string[] s1 = ["a", "b", "c"]; 
    immutable(string)[] s2 = ["d", "e", "f"]; 

    s2 = s2[1..$]; // This is what std.array.popFront does under the hood. 
    assert(s2 == ["e", "f"]); // Passes. 
    s2[1] = "g";  // Error: Can't modify immutable data. 

    s1 = s1[1..$]; // Error: Can't modify immutable data. 
    s1[1] = "g"; // Error: Can't modify immutable data. 
} 

immutable string[]隐式转换为immutable(string)[]但隐函数模板实例(通常表示IFTI,这是什么来实例化indexOf模板)是不够聪明尝试。

+0

我明白了。有没有办法获得一个元素的索引在一个不可变的集合中,还是我应该封装这些数组,让它们变成私有的,创建访问器并滚动我自己的indexOf? – fwend 2011-03-31 14:09:08

+0

@fwend:现在最简单的方法是将其转换为可变头。例如:'immutable(string)[] headMutable = symbols;',然后做'headMutable'而不是'symbols'。 – dsimcha 2011-03-31 14:28:48

+0

你知道任何解决这个问题的建议吗?不能在不可变数组上使用'indexOf'是一个相当大的问题。 – 2011-03-31 23:58:54

4

我认为这是std.algorithm中的一个错误。如果删除immutable限定符,则代码将按原样运行。我认为indexOf/countUntil应该工作在immutable阵列,但目前它没有。

你可以使他们明显常量(在每个声明之前enum),它似乎工作。 Amusingly, this may also be a bug

+0

我注释掉了不可变块,它现在可以工作 – fwend 2011-03-31 13:45:06

3

道歉破损;我介绍了它。我同意dsimcha的描述和建议的修复。

我们正在考虑对此语言进行简单的更改以说明此简单情况。当将合格类型的值传递给函数时,会自动剥离一个限定符级别。通过那个(现在是假设的)规则,限定符(T [])将成为(当传递给函数时)限定符(T)[]和限定符(T *)将成为限定符(T)*。这可以让你的例子工作。缺点是函数不能区分顶级限定符,但我相信这不会损害任何具体的用途。

+0

How这可以用'ref'传递'class'类型和'struct'吗?你不能只剥离一个“不可变的”,否则不可变的对象在函数内部突然变得可变。这种假设的规则闻起来很腥,听起来像是稍后会以微妙的方式引起问题的事情。 – 2011-04-01 11:59:01

+0

@Peter:首先,有一个由Michel Fortin编写的实验性补丁,它引入了对不可变类对象的可变引用。其次,人们倾向于将不可变数组存储为例如静态表很常见,但通常不会操纵一个不可变的一般范围。话虽如此,我同意一个更一般的规则是可取的。 – 2011-04-02 06:14:05