假设我有一个名为Tool的类:
class Tool
def initialize( name, weight )
@name = name
@weight = weight
end
attr_reader :name, :weight
attr_writer :name, :weight
def to_s
name + " " + weight
end
end
但如果我愿意,这个Tool
可以是一个人:
hammer = Tool.new( "Hammer", 14.5 )
pp = Tool.new( "first", "last" )
它很灵活,因为我可以创建一种类型并用于多种用途。但是,如果用户意外输错,肯定会导致错误的数据类型,我们如何跟踪问题呢? 这个想法有哪些优点和缺点?
答案 0 :(得分:6)
Ruby根本没有松散的输入。恰恰相反,它的输入非常强烈。但是它也是动态类型(与静态类型相反,例如C ++和Java)。你应该对差异做一些阅读。 PHP是一种松散类型语言的例子。
回答你的问题,如果不使用测试驱动开发,动态类型的语言(如Ruby和Python)很难以任何复杂性编写。也就是说,首先尝试编写测试以解释期望并定义类和API,以便人们只需使用常识就可以知道如何使用它们。如果您真的担心客户端将无效类型传递给您的方法,那么如果类型不正确,您始终可以键入检查并抛出异常。但是,这通常不是在系统范围内完成的。
答案 1 :(得分:2)
大多数语言中的静态类型(好吧,Java和朋友,我不在这里考虑Haskell家族)会使程序变得冗长并过度约束它们,而在设计层面几乎没有回报。在两个对象之间建立关系时,重要的是它们扮演的角色和责任,而不是它们的类型,因此静态类型会使您在错误的层次上思考。
关于健壮性,就像空指针一样,类型错误通常会导致灾难性的失败,因此它们永远不会被长期检测不到。所以恕我直言,静态类型阻止的错误类别并不那么有趣。另一方面,任何人都可以写Tool.new( "Hammer", -42 )
哪个类型是正确的,但负重可能会导致非常奇怪的行为而不会失败。那是因为该参数的作用是 weight ,它永远不会消极,你不能用简单的数字类型来表达。所以在设计时真正需要的不是静态类型,而是埃菲尔的验证或合同。
现在,考虑一些意料之外的软件演变:您希望集成对SI单元的支持。您是否明白为什么静态输入该参数的设计决定现在看起来像是过早的?在动态类型系统中,更容易制作一个知道算术的新对象,但要考虑单位转换,并直接用它来代替现有代码中的数字。
当然,静态类型具有文档价值,动态类型语言需要在该领域有一些规则,即清晰的命名,良好的测试,良好的评论......但无论如何,这些都不是静态打字的多余。
答案 2 :(得分:1)
我不会将其描述为松散或动态类型 - 而是将其用于两个不同的目的。通常,您不应该创建一个通用的类来存储完全不同的数据集。
您提到的方法的缺点正如您所提到的 - 用户混淆和潜在的错误数据。您应该创建第二个类Person
来处理作为人的对象。它消除了混淆,并且用户没有可能输入拼写错误并创建错误的数据类型。
[编辑]
为防止用户输入错误数据,您可以修改attr_writer创建的weight=
方法,如下所示:
def weight= value
@weight = value.to_i # only store integers
end
或者检查输入的字符串是否实际上是一个数字,如果没有则引发异常。