我认为奇怪的是,只有 C# 和 Java 程序员似乎遭受了一种痛苦,使他们无法从代码上下文中提取信息,而 Python、JavaScript、Ruby、F#、Haskell 和其他开发人员似乎对此免疫。为什么他们看起来做得很好,但我们 C# 程序员需要有这个讨论?
如果前面的显式类型声明是草率或懒惰的,这是否意味着没有高质量、可读的 Python 代码?事实上,不是很多人称赞 Python 的可读性吗?JavaScript 中的动态类型有很多让我讨厌的地方,但缺少显式类型声明并不是其中之一。
静态类型语言中的类型推断应该是常态,而不是例外;它减少了视觉上的混乱和冗余,同时在您明确指定类型时使您的意图更加清晰,因为您想要一个较少派生的类型 ( IList<int> list = new List<int>();
)。
有些人可能会反对var
这样的案例:
var c = SomeMethod();
好吧,我会说你应该给你的变量更明智的名字。
改进:
var customer = SomeMethod();
更好的:
var customer = GetCustomer();
让我们尝试显式输入:
Customer customer = GetCustomer();
你现在有什么以前没有的信息?你现在肯定知道它是 type Customer
,但你已经知道了,对吧?如果您已经熟悉该代码,那么您customer
只需通过变量的名称就知道可以使用哪些方法和属性。如果你还不熟悉代码,你不知道有什么方法Customer
有什么办法。这里的显式类型没有增加任何价值。
也许一些反对者var
可能会承认,在上面的例子中,var
并没有什么坏处。但是,如果一个方法不返回一个简单且众所周知的类型,如Customer
, 或Order
,而是一些已处理的值,如某种 Dictionary 怎么办?就像是:
var ordersPerCustomer = GetOrdersPerCustomer();
我不知道返回的是什么,可能是字典、列表、数组,任何东西。但这有关系吗?从代码中,我可以推断出我将拥有一个可迭代的客户集合,其中每个客户Customer
又包含一个可迭代的Order
. 我真的不在乎这里的类型。我知道我需要知道什么,如果事实证明我错了,那是方法的错误,它用它的名字误导了我,这是无法通过显式类型声明来解决的。
让我们看一下显式版本:
IEnumerable<IGrouping<Customer,Order>> ordersPerCustomer = GetOrdersPerCustomer();
我不了解你,但我发现从中提取我需要的信息要困难得多。至少不是因为包含实际信息(变量名)的位更靠右,我的眼睛需要更长的时间才能找到它,在视觉上被所有那些疯狂的<
和>
. 实际的类型毫无价值,它是 gobbledygook,特别是因为要理解它,您需要知道那些泛型类型的作用。
如果您在任何时候都不确定方法的作用或变量包含的内容,仅从名称中,您应该给它一个更好的名称。这比看它是什么类型更有价值。
不应该需要显式输入,如果是,那么您的代码有问题,而不是类型推断。不需要它,因为其他语言显然也不需要它。
也就是说,我确实倾向于对“原始”使用显式类型,例如int
and string
。但老实说,这更多是一种习惯,而不是有意识的决定。但是,对于数字,如果您忘记将 添加m
到要键入为的文字数字中,类型推断可能会让您感到困惑decimal
,这很容易做到,但是编译器不会让您意外丢失精度,所以它不是一个实际的问题。事实上,如果我在var
任何地方都使用它,那么在我处理的大型应用程序中从整数到十进制数的数量变化会容易得多。
这是另一个优点var
:它允许快速实验,而不会强迫您在各处更新类型以反映您的更改。如果我想将上面的示例更改为Dictionary<Customer,Order>[]
,我可以简单地更改我的实现,并且所有调用它的代码都var
将继续工作(嗯,至少是变量声明)。