如何使用Ruby Duck打字

我正在学习Ruby,而且我有一个关于打字的重大概念问题。 请允许我详细说明为什么我不理解范式。

假设我在Ruby中使用简洁代码链接方法。 我必须准确地知道链中每个方法调用的返回类型,否则我不知道下一个链接上有哪些方法可用。 我每次都必须检查方法文档吗? 我正在遇到这个不断运行的教程练习。 我似乎陷入了一个引用过程,推断,运行,失败,修复,重复以使代码运行,而不是确切地知道我在编码期间正在使用什么。 面对Ruby对直觉性的承诺,这种情况变得苍白无力。

假设我正在使用第三方库,我需要知道哪些类型允许传递参数,否则我会失败。 我可以查看代码,但可能有也可能没有任何注释或声明该方法所期望的类型。 我理解您基于方法的代码可用于对象,而不是类型。 但是我必须确定我传递的任何参数都包含库所期望的所有方法,所以我仍然需要进行类型检查。 我是否必须希望并祈祷所有内容都在接口上正确记录,所以我知道我是否应该给出一个字符串,一个哈希,一个类等等。

如果我查看方法的来源,我可以获得一个被调用的方法列表并推断出预期的类型,但我必须执行分析。

Ruby和duck打字:合同设计不可能?

前面的stackoverflow问题中的讨论并没有真正回答除了“你必须遵循的流程”之外的任何事情,而且这些流程似乎不是标准的,每个人对要遵循的流程有不同的看法,并且语言有零执法。 方法validation? 测试驱动设计? 记录的API? 严格的方法命名约定? 什么是标准,谁来决定它? 我该怎么做? 这些指南是否会解决这个问题? https://stackoverflow.com/questions/616037/ruby-coding-style-guidelines ? 编辑有帮助吗?

从概念上讲,我也没有获得优势。 您需要知道所调用的任何方法需要哪些方法,因此无论您在编写任何代码时都在键入。 您只是没有明确告知语言或其他任何人,除非您决定将其记录下来。 然后你就会在运行时而不是在编码期间进行所有类型检查。 我已经完成了PHP和Python编程,我也不了解它。

我错过了什么或不理解? 请帮助我理解这个范例。

这不是Ruby特有的问题,对于所有动态类型语言都是一样的。

通常没有关于如何记录这一点的指南(并且大部分时间都不可能)。 请参阅ruby文档中的示例map

 map { |item| block } → new_ary map → Enumerator 

这里的itemblocknew_ary是什么以及它们如何相关? 除非你知道实现或者可以以某种方式从函数的名称推断它,否则无法判断。 指定类型也很难,因为new_ary取决于哪个block返回,而这又取决于item的类型,对于Array中的每个元素,它可能是不同的。

很多时候,你还会偶然发现一个文档,说明参数是Object类型,因为一切都是Object ,所以它再次告诉你什么。

OCaml有一个解决方案,它支持结构类型,因此需要一个具有属性foo的对象的函数将被推断为{ foo : String }而不是具体类型。 但是OCaml仍然是静态类型的。

值得注意的是,这也可能是静态类型语言中的问题。 Scala在集合上有非常通用的方法,导致类型签名如++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Array[T], B, That]): That附加两个集合。

因此,大多数情况下,您只需要在动态类型语言中学习这一点,并且可能有助于改进您正在使用的库的文档。

这就是为什么我更喜欢静态打字;)

编辑可能有意义的一件事是做Scala也做的事情。 它实际上并没有默认显示++[B](that: GenTraversableOnce[B]): Array[B]类型签名,而是显示++[B](that: GenTraversableOnce[B]): Array[B]不是通用的,但可能涵盖大部分用途案例。 所以对于Ruby的地图,它可以有一个单形类型的签名,如Array -> (a -> b) -> Array 。 它仅对于列表仅包含一种类型的值并且块仅返回另一种类型的元素的情况才正确,但它更容易理解并且更好地概述了该函数的作用。

考虑强类型语言(C ++,Java,C#等)的设计选择强制执行传递给方法的类型的严格声明,以及方法返回的类型。 这是因为这些语言旨在validation参数是否正确(并且由于这些语言已编译,因此可以在编译时完成此工作)。 但有些问题只能在运行时得到解答,例如C ++有RTTI(运行时类型解释器)来检查和强制执行类型保证。 但作为开发人员,您将受到语法,语义和编译器的指导,以生成遵循这些类型约束的代码。

Ruby使您可以灵活地获取动态参数类型,并返回动态类型。 这种自由使您能够编写更通用的代码(在STL和generics编程上阅读Stepanov),并为您提供一组丰富的内省方法(is_a?,instance_of?,respond_to?,kind_of?,is_array?等)。可以动态使用。 Ruby允许您编写generics方法,但您也可以通过合同明确强制执行设计,并通过选择的方式处理合同失败。

是的,在将方法链接在一起时需要小心,但学习Ruby不仅仅是一些新的关键词。 Ruby支持多种范式; 你可以编写程序,对象oriend,generics和function程序。 当您了解Ruby时,您现在所处的循环将会迅速改善。

也许你的担忧源于对强类型语言的偏见(C ++,Java,C#等)。 鸭子打字是一种不同的方法。 你的想法不同。 鸭子打字意味着如果一个物体看起来像一个,表现得像一个,那么它就是一个。 一切(差不多)都是Ruby中的一个对象,所以一切都是多态的。

考虑模板(C ++有它们,C#有它们,Java有它们,C有宏)。 您构建算法,然后让编译器为您选择的类型生成实例。 你不是通过与generics合同进行设计,但是当你认识到它们的力量时,你会编写更少的代码并生成更多代码。

你还有一些其他问题,

  • 第三方图书馆(gem)并不像你担心的那样难以使用
  • 记录的API? 见Rdoc和http://www.ruby-doc.org/
  • (通常)为库提供Rdoc文档
  • 编码指南 – 查看初学者的几个简单gem的来源
  • 命名惯例 – 蛇案和骆驼案都很受欢迎

建议 – 以开放的心态学习在线教程,做教程( http://rubymonk.com/learning/books/是好的),你将有更多的焦点问题。

是的,你似乎误解了这个概念。 它不是静态类型检查的替代品。 这是不同的 。 例如,如果将对象转换为json(用于将它们呈现给客户端),则只要它具有#to_json方法,就不关心对象的实际类型。 在Java中,您必须创建IJsonable接口。 在ruby中不需要开销。

至于知道什么通过哪里和什么返回什么:记住这个或每次咨询文档。 我们都这样做。

再过一天,我看到有超过6年经验的铁路程序员在Twitter上抱怨他无法记住alias_method的参数顺序:新名称是先行还是最后?

面对Ruby对直觉性的承诺,这种情况变得苍白无力。

并不是的。 也许它只是写得很糟糕的库。 我敢说,在核心ruby中,一切都非常直观。

具有强大IDE的静态类型语言在这里有一个小优势,因为它们可以非常快速地向您显示文档。 不过,这仍然是访问文档。 只是更快。