我有一个递归算法,逐个字符地逐步执行字符串,并解析它以创建树状结构。我希望能够跟踪解析器当前所处的字符索引(对于错误消息和其他任何内容),但我并不热衷于实现类似于元组的处理多个返回类型的东西。
我尝试使用在方法外部声明并传递到递归方法的Integer类型,但因为它是最终的,所以当我返回时,递归调用增量被“遗忘”。 (因为Integer值的增量使得值传递值的对象引用点在新对象上)
有没有办法得到类似的工作,不会污染我的代码?
答案 0 :(得分:2)
这是一种黑客行为,但有时我会使用一个可变的AtomicInteger来做这样的事情。我也看到了传入大小为1的int []的情况。
答案 1 :(得分:2)
我目前使用的解决方案是:
int[] counter = {0};
然后将其传递给递归算法:
public List<Thing> doIt (String aString, int[] counter) { ... }
当我想增加它时:
counter[0]++;
不是超级优雅,但它有效...
答案 2 :(得分:2)
整数是不可变的,这意味着当您将其作为参数传递时,它会创建副本而不是对同一项的引用。 (explanation)。
要获得您正在寻找的行为,您可以编写自己的类,就像Integer一样只是可变的。然后,只是将它传递给递归函数,它在递归中递增,当递归结束后再次访问它时,它仍将保持其新值。
编辑:请注意,使用int []数组是此方法的变体...在Java中,数组也通过引用传递,而不是像原语或不可变类一样复制。
答案 3 :(得分:2)
既然你已经发现了伪可变整数“hack”,那么这个选项怎么样:
您是否有必要制作单独的Parser课程?如果执行此操作,则可以将当前状态存储在成员变量中。您可能需要考虑如何处理任何线程安全问题,并且对于此特定应用程序可能有点过分,但它可能对您有用。
答案 4 :(得分:1)
你可以使用一个静态int类变量,每次调用doIt方法时它都会递增。
答案 5 :(得分:1)
你也可以这样做:
private int recurse (int i) {
if (someConditionkeepOnGoing) {
i = recurse(i+1);
}
return i;
}
答案 6 :(得分:0)
老实说,我会重新编写函数,使其成为一个使用循环的线性算法。这样,如果您单步执行非常大的字符串,则无法用尽堆空间。此外,您不需要额外的参数来跟踪计数。
这也可能会使算法更快,因为它不需要为每个字符进行函数调用。
除非有特定原因,否则需要递归。
答案 7 :(得分:0)
我能想到的一种可能性是将计数存储在类的成员变量中。这当然假设公共doIt
方法仅由单个线程调用。
另一个选择是重构public方法来调用私有帮助器方法。 private方法将列表作为参数并返回计数。例如:
public List<Thing> doIt(String aString) {
List<Thing> list = new ArrayList<Thing>();
int count = doItHelper(aString, list, 0);
// ...
return list;
}
private int doItHelper(String aString, List<Thing> list, int count) {
// ...
// do something that updates count
count = doItHelper(aString, list, count);
// ...
return count;
}
这假设您可以在公共doIt
方法中执行错误处理,因为count
变量实际上并未传递回调用方。如果你需要这样做,你当然可以抛出异常:
public List<Thing> doIt(String aString) throws SomeCustomException {
List<Thing> list = new ArrayList<Thing>();
int count = doItHelper(aString, list, 0);
// ...
if (someErrorOccurred) {
throw new SomeCustomException("Error occurred at chracter index " + count, count);
}
return list;
}
如果不了解更多关于算法实际工作情况的信息,很难知道这是否会有所帮助。