2013-10-03 37 views
8

我正在学习Ruby,我有一个关于打字的重大概念问题。请允许我详细说明为什么我不了解范式。如何使用Ruby Duck Typing

假设我是Ruby中的简洁代码的方法链接。我必须精确地知道链中每个方法调用的返回类型,否则我不知道下一个链接上有哪些方法可用。我每次都必须检查方法文档吗?我遇到了这个不断运行的教程练习。看来我坚持一个参考过程,推断,运行,失败,修复,重复以获得代码运行,而不是知道我在编码期间正在处理的内容。这在Ruby的直觉性承诺面前飞来飞去。

说我正在使用第三方库,我再一次需要知道哪些类型允许传递参数,否则我会失败。我可以看看代码,但是可能会有也可能没有任何关于该方法所期待的类型的评论或声明。我理解你基于方法的代码是可用的对象,而不是类型。但是,我必须确定无论我传递的参数是否具有库所需的所有方法,所以我仍然需要进行类型检查。我是否希望并祈祷一切都在接口上正确记录,以便我知道是否需要给出字符串,哈希,类等。

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

Ruby and duck typing: design by contract impossible?

在前面的计算器问题的讨论没有真正回答不是“有你必须遵循流程”和这些进程似乎并不为标准的其它任何东西,每个人都有不同的意见遵循什么程序,以及该语言的执行力度为零。方法验证?测试驱动设计?记录的API?严格的方法命名约定?标准是什么,谁决定它?我遵循什么?这些指导方针是否可以解决这个问题https://stackoverflow.com/questions/616037/ruby-coding-style-guidelines?有编辑帮忙吗?

从概念上讲,我也没有得到好处。您需要知道所调用的任何方法需要哪些方法,因此无论您在编写任何代码时都正在输入内容。除非您决定对其进行记录,否则您只是没有明确告知该语言或任何其他人。然后,你被困在做所有类型检查在运行时而不是在编码过程中。我已经完成了PHP和Python编程,但我也不明白。

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

+2

鸭子打字有一定的优势,但当然也有缺点。我可以将* any *对象传递给一个方法'foo(a)',它只要调用'a.responds_to?(:bar)'就可以调用'a.bar'。这很好。没有界面,没有泛型,只需添加一个'bar'方法即可。当然,静态打字也有很多优点。听起来你只需要一些Ruby方式的经验来欣赏两者。也听起来像你可能被intellisense(或类似的功能)有点被宠坏了。许多(*许多*)我们必须尽早且经常地检查文档。 –

+2

直觉是训练的结果,所以没有直觉,直到你训练自己使用它。 –

+0

这个问题患有“TL; DR”。它会帮助你总结它,并抛弃其他方面,否则它太广泛了。 “这直接面对Ruby对直觉的承诺。”对谁是直观的? Matz说,它的设计对他来说很直观,而且他认为对于那些已经充分使用它的人来说,这会变得直观。创建一种立即对所有人都直观的语言是不可能的,所以他的目标就是点亮。 –

回答

1

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

至于知道什么传递什么,什么返回什么:记住这个或每次咨询文档。我们都这样做。

又一天,我看到有6年以上的使用经验的rails程序员在twitter上抱怨说,他无法记忆alias_method的参数顺序:新名字先走还是后走?

这就是Ruby面对直觉的承诺。

不是真的。也许这只是写得不好的图书馆。在核心ruby中,我敢说,一切都很直观。

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

+1

我认为你已经接近我的目标了。正如你所说,你会声明IJsonable。在Ruby中你不会声明这一点。那么你怎么知道你需要这个接口?正如你所说,你必须查阅文档,文档必须声明你需要这个接口,否则没有检查代码就无法知道。那么有什么好处,你必须在文档中声明,为什么不用代码声明它,然后你的IDE知道接口,并且可以为你自动实现事情。什么是声明你的界面的开销。 – kamegami

+0

接口的开销是系统中的另一个实体。这个你遇到麻烦的图书馆是什么?大部分与我一起工作的,他们都接受基元(字符串,数组,哈希等)(这在文档中是显而易见的)或来自同一个库的对象(它们再次被记录)。 –

+0

如果您给某个方法提供了错误的对象,则会引发错误。这将通过测试来检测。 –

4

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

通常有对如何可以记录这个(和大部分时间不是真的有可能)没有准则。红宝石文档

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

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

很多时候你还偶然发现的文件,指出一种说法是Object类型,这再次告诉你什么,因为一切都是对象的。

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

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

所以大多数的时候,你就只能通过心脏的动态类型语言学习这,或许有助于提高您使用的库文件。

这就是为什么我喜欢静态类型;)

编辑一两件事,可能是有意义的是做什么斯卡拉也做。它实际上并未向您显示++的类型签名默认情况下,它显示++[B](that: GenTraversableOnce[B]): Array[B]这不是通用的,但可能涵盖大部分用例。所以对于Ruby的地图,它可以有一个单形签名,如Array<a> -> (a -> b) -> Array<b>。对于列表只包含一个类型值并且该块只返回另一个类型的元素的情况,这只是正确的,但它更容易理解,并且很好地概述了该函数的功能。

+0

您已经击中了头部,这是我确切的问题。 – kamegami

2

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

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

是的,你需要链接方法时在一起,但学习Ruby不仅仅是一些新的关键字来照顾。 Ruby支持多种范例;你可以编写程序,对象oriend,通用和功能程序。当你了解Ruby时,你现在正在使用的循环会很快得到改善。

也许你的关注从对强类型语言(C++,Java和C#等)偏置茎。鸭子打字是一种不同的方法。你有不同的想法。鸭子打字意味着,如果一个物体看起来像一个,行为像一个,那么它是一个。一切(几乎)都是Ruby中的一个对象,所以一切都是多态的。

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

你的一些其他问题,

  • 第三方库(宝石),是不是很难,因为你害怕
  • 说明的API使用?见RDOC和http://www.ruby-doc.org/
  • RDoc文档(通常)提供的库
  • 编码准则 - 看看源对于初学者
  • 命名约定的几个简单的宝石 - 蛇情况和骆驼都流行

建议 - 接近一个在线教程,以开放的心态,做教程(http://rubymonk.com/learning/books/好),你将有更集中的问题。

+0

这似乎是我正在寻找的答案。所以我应该通过对参数进行适当的运行时检查来执行自检。然后你必须生成文档来代替类型或接口声明。文档是否可以通过内省检查生成?如果说PEP8相当于指出并说“这样做是错误的”,那么我会觉得更加自在。 – kamegami

+0

@ kamegami:Ruby的内省不会从代码中发现预期的类型,所以无法在没有帮助的情况下生成完整的文档。但是,诸如'yard'之类的doc工具允许编码人员为params声明类型并返回值。因此你依靠图书馆开发者的良好意图和文档。如果你有时间和倾向,可以写出非常全面和准确的文件。 –

+0

似乎是否有用于声明参数意图的标准约定(我将调用具有您期望的接口的对象),您可以在一次犯规中处理接口文档,错误处理和IDE静态意图分析(Intellisense风格)一举。我不能成为唯一一个认为这是动态类型语言的人。 – kamegami