API 设计中的 (start, end) 与 (start, length)

(start, end) vs. (start, length) in API design

提问人:mikera 提问时间:1/11/2013 最后编辑:Brian Tompsett - 汤莱恩mikera 更新时间:11/14/2023 访问量:788

问:

我见过在指定索引范围时使用的两个替代约定,例如

subString(int startIndex, int length);

与。

subString(int startIndex, int endIndex);

就您可以对它们执行的操作而言,它们显然是等效的,唯一的区别是您是指定结束索引还是范围的长度。

我假设在所有情况下都是包容性和排他性的。startIndexendIndex

在定义 API 时,是否有任何令人信服的理由偏爱其中一种?

与语言无关的 API 设计

评论

0赞 om-nom-nom 1/12/2013
顺便说一句,我认为最好使用 firstIndex/lastIndex - 对于开始/结束索引,是否包含 endIndex 的元素是一个悬而未决的问题,因此必须深入研究文档。

答:

7赞 Damien_The_Unbeliever 1/11/2013 #1

我更喜欢那个,因为它让我在文档中少了一个要问/查找的问题。length

对于基础 - 这是一个包容性的还是排他性的终点?endIndex

(对于任何一种变体,都可以问同样的问题,但这将是一个反常的 API,使其具有排他性)。startIndex

2赞 Marc Baumbach 1/11/2013 #2

这是一个很好的问题,我认为使用哪种偏好归结为最常见的用例是什么。大多数用例使用任一 API 都同样简单,但请考虑以下一个:

您希望获取从 5 开始并在字符串末尾结束的子字符串。使用基于索引的版本(假设它是第二个索引是独占的),它就像以下几点一样简单:

str.subString(5, str.length());

使用基于长度的 API:

str.subString(5, str.length() - 5);

第二种方法不那么简洁和明显。但是,这可以通过简单地声明如果长度会导致剩余字符串溢出来解决,它将优雅地支持它(例如 会抓取从索引 5 到末尾的所有内容,即使它可能要求的字符多于剩余的字符)。Ruby 除了支持负索引等高级功能外,还使用他们的 String#splice 方法做到这一点。str.subString(5, str.length());

在我看来,基于指数的方法更具体,尤其是在不允许负指数的情况下。这使得对 API 的期望非常明显,这可能是一件好事;使自己更难搬起石头砸自己的脚。然而,一个有据可查的 API,比如 Ruby,可以很容易地赋予程序员权力,并且可以进行一些优雅的子字符串。

我还发现,一般来说,当我执行子字符串操作时,我经常知道我的起点和终点。使用基于长度的方法,在调用 API 时需要额外的计算(例如 )。substring(startIndex, endIndex - startIndex)

3赞 aka.nice 1/12/2013 #3

如何消除立场论点的歧义......

  1. 使用较长的名称 subStringFromUpto( startIndex , stopIndex )

  2. 在整个库中使用统一的约定

这么多年过去了,我们不是发现好多了吗?

啊,是的,也许在 Smalltalk 中,因为这个问题被标记为与语言无关......

aString copyFrom: startIndex to: stopIndex.
aString substringOfLength: length startingAt: startIndex.

不那么模棱两可,但也许我们还要再等 30 年才能更广泛地采用这种风格
(它可能看起来太简单了,不严肃)

1赞 George Forman 7/14/2016 #4

有人应该对典型的呼叫站点进行研究,以找出哪种方法会产生更简洁的代码(因此可能是正确的代码)。

我喜欢这样一种观点,即使用“长度”您不必查看文档,但您可能已经在查看文档以确定第二个整数是“结束”还是“长度”。如果你把它命名为 endExclusive,那么它就像是自记录的一样。