我看到已经有很多好的答案。我将重复其中的一些,但有时您只想用自己的话说。我将用C ++的一些示例进行评论,因为这是我最熟悉的语言。
必要的事情永远都不是不明智的。类型推断对于使其他语言功能切实可行是必需的。在C ++中,可能有无法说明的类型。
struct {
double x, y;
} p0 = { 0.0, 0.0 };
// there is no name for the type of p0
auto p1 = p0;
C ++ 11添加了同样难以言喻的lambda。
auto sq = [](int x) {
return x * x;
};
// there is no name for the type of sq
类型推断也支持模板。
template <class x_t>
auto sq(x_t const& x)
{
return x * x;
}
// x_t is not known until it is inferred from an expression
sq(2); // x_t is int
sq(2.0); // x_t is double
但是您的问题是“为什么我(程序员)为什么在阅读代码时要推断变量的类型?对于每个人来说,阅读类型是否比思考其中的类型更快?”
类型推断可消除冗余。在阅读代码时,有时在代码中包含冗余信息可能会更快,更容易,但是冗余会掩盖有用的信息。例如:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
C ++程序员不需要很熟悉标准库就可以确定i是迭代器,i = v.begin()
因此显式类型声明的价值有限。通过它的存在,它会遮盖更重要的细节(例如,i
指向矢量的开头)。@amon的很好答案提供了一个更好的例子,详细程度使重要细节难以理解。相比之下,使用类型推断则使重要细节更加突出。
std::vector<int> v;
auto i = v.begin();
尽管阅读代码很重要,但这还不够,但是在某些时候,您将不得不停止阅读并开始编写新代码。代码冗余使修改代码变得越来越慢。例如,说我有以下代码片段:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
在我需要更改向量的值类型的情况下,将代码加倍更改为:
std::vector<double> v;
std::vector<double>::iterator i = v.begin();
在这种情况下,我必须在两个地方修改代码。与类型推断相反,原始代码为:
std::vector<int> v;
auto i = v.begin();
以及修改后的代码:
std::vector<double> v;
auto i = v.begin();
请注意,我现在只需要更改一行代码。将其推断到大型程序中,类型推断可以比使用编辑器更快地将更改传播到类型。
代码冗余会产生错误。每当您的代码依赖于两条信息保持相等时,就有可能出错。例如,此语句中的两种类型之间存在不一致,这可能不是故意的:
int pi = 3.14159;
冗余使意图难以辨别。在某些情况下,类型推断可以比显式类型规范更容易阅读和理解。考虑一下代码片段:
int y = sq(x);
在sq(x)
返回an 的情况下,int
是否y
为an 并不明显,int
因为它是的返回类型sq(x)
或因为它适合使用的语句y
。如果我更改其他代码以使其sq(x)
不再返回int
,则仅从该行就不能确定是否y
应更新的类型。与相同的代码对比,但使用类型推断:
auto y = sq(x);
在这种情况下,意图很明确,y
必须与所返回的类型相同sq(x)
。当代码更改的返回类型时sq(x)
,y
更改的类型将自动匹配。
在C ++中,还有第二个原因,上面的示例使用类型推断更简单,类型推断不能引入隐式类型转换。如果返回类型sq(x)
不是int
,则编译器会静默插入到的隐式转换int
。如果的返回类型sq(x)
是定义的类型复杂类型operator int()
,则此隐藏函数调用可能是任意复杂的。