像这样的东西(是的,这不处理一些边缘情况——这不是重点):
int CountDigits(int num) { int count = 1; while (num >= 10) { count++; num /= 10; } return count; }
您对此有何看法?也就是说,使用函数参数作为局部变量。
两者都放在堆栈上,并且在性能方面几乎相同,我想知道这方面的最佳实践方面。
当我向由int numCopy = num
.
你怎么看?应该避免这种情况吗?
像这样的东西(是的,这不处理一些边缘情况——这不是重点):
int CountDigits(int num) { int count = 1; while (num >= 10) { count++; num /= 10; } return count; }
您对此有何看法?也就是说,使用函数参数作为局部变量。
两者都放在堆栈上,并且在性能方面几乎相同,我想知道这方面的最佳实践方面。
当我向由int numCopy = num
.
你怎么看?应该避免这种情况吗?
作为一般规则,我不会将函数参数用作本地处理变量,即我将函数参数视为只读。
在我看来,直观易懂的代码对于可维护性至关重要,而修改函数参数以用作本地处理变量往往与该目标背道而驰。我已经开始期望参数在方法的中间和底部具有与顶部相同的值。 另外,一个恰当命名的本地处理变量可以提高可理解性。
尽管如此,正如@Stewart 所说,这条规则或多或少的重要取决于函数的长度和复杂性。对于像您展示的那样简短的简单函数,简单地使用参数本身可能比引入新的局部变量更容易理解(非常主观)。
countDigits()
不过,如果我要写remainingBalance
一些num
像
有时,我会在方法的开头修改一个局部参数来规范化参数:
void saveName(String name) {
name = (name != null ? name.trim() : "");
...
}
我认为这没关系,因为:
一个。在方法的顶部很容易看到,
湾。参数保持其最初的概念意图,并且
C。该参数对于该方法的其余部分是稳定的
再说一次,有一半的时间,无论如何我都喜欢使用局部变量,只是为了final
在那里获得几个额外的 s (好吧,这是一个不好的理由,但我喜欢final
):
void saveName(final String name) {
final String normalizedName = (name != null ? name.trim() : "");
...
}
如果在 99% 的情况下,代码未修改函数参数(即,对于此代码库来说,变异参数是不直观的或意外的),那么在另外 1% 的时间里,在顶部删除关于变异参数的快速注释一个长/复杂的函数可能对可理解性有很大帮助:
int CountDigits(int num) {
// num is consumed
int count = 1;
while (num >= 10) {
count++;
num /= 10;
}
return count;
}
PS :-)
参数与参数
http://en.wikipedia.org/wiki/Parameter_(computer_science)#Parameters_and_arguments
这两个术语有时可以松散地互换使用。特别是,有时使用“参数”代替“参数”。尽管如此,还是有区别的。正确地,参数出现在过程定义中;参数出现在过程调用中。
所以,
int foo(int bar)
bar
是一个参数。
int x = 5
int y = foo(x)
的值x
是参数的bar
参数。
当我这样做时,我总是觉得有点好笑,但这并不是避免它的好理由。
您可能希望避免它的一个原因是出于调试目的。当您调试到一半时,能够分辨“暂存器”变量和函数输入之间的区别会非常有用。
我不能说这是在我的经验中经常出现的东西-通常你会发现值得引入另一个变量只是为了具有不同的名称,但是如果最干净的代码最终会改变值的变量,那就这样吧。
出现这种情况并且完全合理的一种情况是,您有一些值意味着“使用默认值”(通常是 Java 或 C# 等语言中的空引用)。在那种情况下,我认为将参数的值修改为“真实”默认值是完全合理的。这在 C# 4 中特别有用,您可以有可选参数,但默认值必须是常量:
例如:
public static void WriteText(string file, string text, Encoding encoding = null)
{
// Null means "use the default" which we would document to be UTF-8
encoding = encoding ?? Encoding.UTF8;
// Rest of code here
}
关于 C 和 C++:
我的观点是使用参数作为函数的局部变量很好,因为它已经是局部变量。那么为什么不这样使用它呢?
将参数复制到新的局部变量中只是为了使用可修改的变量时,我也觉得很傻。
但我认为这几乎是个人意见。随心所欲地做。如果你因此觉得复制参数很无聊,说明你的性格不喜欢它,你不应该这样做。
如果我不需要原始值的副本,我不会声明新变量。
IMO 我不认为改变参数值通常是一种不好的做法,
这取决于您将如何在代码中使用它。
我的团队编码标准建议不要这样做,因为它可能会失控。在我看来,对于您展示的功能,这并没有什么坏处,因为每个人都可以看到正在发生的事情。问题是随着时间的推移,函数会变得更长,并且它们会修复错误。一旦一个函数的代码不止一个屏幕,这就会开始变得混乱,这就是我们的编码标准禁止它的原因。
编译器应该能够很容易地摆脱冗余变量,因此它不会影响效率。这可能只是在您和您的代码审查员之间,这是否可以。
我通常不会更改函数中的参数值。如果稍后在函数中需要引用原始值,您仍然拥有它。在您的简单情况下,没有问题,但是如果您稍后添加更多代码,您可能会在没有意识到它已更改的情况下引用“num”。
代码需要尽可能自给自足。我的意思是你现在依赖于作为算法的一部分传入的内容。如果您团队的其他成员决定将其更改为通过引用传递,那么您可能会遇到大问题。
如果您希望它们是不可变的,那么最好的做法肯定是复制入站参数。
我通常不会修改函数参数,除非它们是指针,在这种情况下我可能会更改指向的值。
我认为这方面的最佳实践因语言而异。例如,在 Perl 中,您可以将任何变量甚至变量的一部分本地化到本地范围,以便在该范围内更改它不会对它之外产生任何影响:
sub my_function
{
my ($arg1, $arg2) = @_; # get the local variables off the stack
local $arg1; # changing $arg1 here will not be visible outside this scope
$arg1++;
local $arg2->{key1}; # only the key1 portion of the hashref referenced by $arg2 is localized
$arg2->{key1}->{key2} = 'foo'; # this change is not visible outside the function
}
有时我会因为忘记本地化通过引用传递给函数的数据结构而感到困扰,我在函数内部进行了更改。相反,我还返回了一个数据结构作为函数结果,该结果在多个系统之间共享,然后调用者错误地更改了数据,从而在通常称为远距离动作的难以追踪的问题中影响了这些其他系统。最好的办法是在返回数据之前克隆数据*,或者将其设为只读**。
*在 Perl 中,查看dclone()
内置Storable模块中的函数。
**在 Perl 中,请参阅 lock_hash()
或lock_hash_ref()
在内置的Hash::Util模块中)。