10

您如何看待单行功能?不好吗?我能想到的一个优点是它使代码更全面(如果你为它选择一个好名字的话)。例如:

void addint(Set *S, int n)
{
     (*S)[n/CHAR_SIZE] |= (unsigned char) pow(2, (CHAR_SIZE - 1) - (n % CHAR_SIZE));
}

我能想到的一个缺点是它减慢了代码速度(将参数推入堆栈、跳转到函数、弹出参数、执行操作、跳回代码 - 并且只针对一行?)

将这些行放在函数中还是将它们放在代码中更好?即使我们只使用一次?

顺便说一句,我还没有发现任何关于此的问题,所以如果以前有人问过这样的问题,请原谅我。

4

8 回答 8

29

不要害怕 1 行函数!

很多程序员似乎对 1 行函数有一个心理障碍,你不应该。

如果它使代码更清晰、更干净,则将该行提取到一个函数中。

性能可能不会受到影响。

在过去十年(也许更远)中制造的任何体面的编译器都会自动内联一个简单的 1 行函数。此外,1 行 C 语言可以轻松对应多行机器代码。你不应该假设即使在理论上你会产生函数调用的全部开销,与你的“一小行”相比,这个开销是显着的。更不用说对应用程序的整体性能有重要意义了。

抽象带来更好的设计。(即使是单行代码)

函数是抽象、组件化代码的主要构建块,它们不应被忽视。如果在函数调用后面封装一行代码使代码更具可读性,那就去做吧。即使在函数被调用一次的情况下。如果您发现注释某一特定代码行很重要,那是一种很好的代码气味,将代码移动到命名良好的函数中可能会有所帮助。

当然,今天的代码可能只有 1 行代码,但是有多少种不同的方式来执行相同的功能呢?将代码封装在函数中可以让您更轻松地查看所有可用的设计选项。也许您的 1 行代码扩展为对 Web 服务的调用,也许它成为数据库查询,也许它变得可配置(例如,使用策略模式),也许您想切换到缓存由您的 1- 计算的值线。当您将 1 行代码提取到自己的函数中时,所有这些选项都更容易实现并且更容易想到。

也许您的 1 行应该是更多行。

如果您有一大块代码,可能很想将大量功能塞进一行代码中,以节省屏幕空间。当您将此代码迁移到函数时,您会减少这些压力,这可能会使您更倾向于将复杂的 1-liner 扩展为占用多行代码的更简单的代码(这可能会提高其可读性和可维护性)。

于 2009-04-24T09:48:04.907 回答
8

我不喜欢将各种逻辑和功能拼到一条线上。您展示的示例是一团糟,可以分成几行,使用有意义的变量名并执行一个接一个的操作。

对于这类问题,我强烈建议您看看(购买、借用、(不要)下载(免费))这本书:Robert C. Martin - Clean Code。这是一本每个开发者都应该看看的书。

它不会立即让你成为一名优秀的程序员,也不会阻止你在未来编写丑陋的代码,但是它会让你在编写丑陋的代码时意识到这一点。它将迫使您以更批判的眼光看待您的代码,并使您的代码像报纸故事一样可读。

于 2009-04-24T09:33:53.350 回答
5

如果多次使用,一定要让它成为一个函数,并让编译器进行内联(可能在函数定义中添加“内联”)。(<这里有关于过早优化的一般建议>)

于 2009-04-24T09:26:13.570 回答
5

由于您的示例似乎使用 C(++) 语法,您可能需要阅读内联函数,以消除调用简单函数的开销。这个关键字只是推荐给编译器,它可能不会内联您标记的所有函数,并且可以选择内联未标记的函数。

在 .NET 中,JIT 将内联它认为合适的方法,但您无法控制它为什么或何时这样做,尽管(据我了解)调试构建永远不会内联,因为这会停止与已编译应用程序匹配的源代码.

于 2009-04-24T09:33:40.200 回答
1

单行功能没有错。如前所述,编译器可以内联函数以消除任何性能损失。

函数也应该比宏更受欢迎,因为它们更容易调试、修改、读取并且不太可能产生意外的副作用。

如果它只使用一次,那么答案就不那么明显了。通过将一些复杂性移到新函数中,将其移至函数可以使调用函数更简单、更清晰。

于 2009-04-24T09:35:16.107 回答
0

如果您在该函数中使用代码 3 次或更多次,那么我建议将其放入函数中。只是为了可维护性。

于 2009-04-24T09:25:37.830 回答
0

什么语言?如果您的意思是 C,我也会使用inline限定符。在 C++ 中,我可以选择inlineboost.lamda或 并向前推进 C++0x 对 lamdas 的原生支持。

于 2009-04-24T09:26:43.477 回答
-1

有时使用预处理器并不是一个坏主意:

#define addint(S, n) (*S)[n/CHAR_SIZE] |= (unsigned char) pow(2, (CHAR_SIZE - 1) - (n % CHAR_SIZE));

当然,您不会得到任何类型的检查,但在某些情况下这可能很有用。宏有其缺点和优点,在少数情况下,它们的缺点可以变成优点。我喜欢在适当的地方使用宏,但何时合适则由您决定。在这种情况下,我会冒昧地说,无论你最终做什么,一行代码都是相当多的。

#define addint(S, n) do { \
    unsigned char c = pow(2, (CHAR_SIZE -1) - (n % CHAR_SIZE)); \
    (*S)[n/CHAR_SIZE] |= c \
  } while(0)
于 2009-04-24T09:41:35.047 回答