几乎从 Java 首次问世以来,我就一直在使用它,但在过去的五年中,我已经厌倦了完成即使是最简单的事情变得多么复杂。在我的精神科医生的推荐下,我开始学习 Ruby,呃,我的意思是我的同事(更年轻、更酷的同事——他们使用 Mac!)。无论如何,他们不断重复的一件事是,与 Java 等较旧、更受打击的语言相比,Ruby 是一种“灵活”的语言,但我真的不知道这意味着什么。有人可以解释是什么让一种语言比另一种语言“更灵活”吗?请。我有点理解动态类型的意义,并且可以看到这对简洁有什么好处。Ruby 语法非常漂亮。还有什么?动态类型是主要原因吗?
7 回答
这也是因为它是无类(在 Java 意义上)但完全面向对象(属性模式),因此即使未定义,您也可以调用任何方法,并且您仍然有最后机会动态响应调用,例如创建方法即时必要。此外,Ruby 不需要编译,因此您可以根据需要轻松更新正在运行的应用程序。此外,一个对象可以在其生命周期内的任何时候通过 mixins 突然从另一个类/对象继承,因此这是另一个灵活性点。无论如何,我同意孩子们的观点,这种称为 Ruby 的语言实际上与 Java 一样长,在很多方面都非常灵活和出色,但我仍然无法同意它是美丽的(语法方面),C 是更漂亮的恕我直言(我是括号的傻瓜),但美丽是主观的,
动态类型并没有接近覆盖它。举一个重要的例子,Ruby 在很多情况下使元编程变得容易。在 Java 中,元编程要么是痛苦的,要么是不可能的。
例如,以 Ruby 的常规方式声明属性:
class SoftDrink
attr_accessor :name, :sugar_content
end
# Now we can do...
can = SoftDrink.new
can.name = 'Coke' # Not a direct ivar access — calls can.name=('Coke')
can.sugar_content = 9001 # Ditto
这不是什么特殊的语言语法——它是 Module 类的一个方法,而且很容易实现。这是一个示例实现attr_accessor
:
class Module
def attr_accessor(*symbols)
symbols.each do |symbol|
define_method(symbol) {instance_variable_get "@#{symbol}"}
define_method("#{symbol}=") {|val| instance_varible_set("@#{symbol}", val)}
end
end
end
这种功能可以让您在表达程序方面有很多,是的,灵活性。
很多看起来像是语言特性的东西(在大多数语言中都是语言特性)只是 Ruby 中的普通方法。再举一个例子,这里我们动态加载我们将其名称存储在数组中的依赖项:
dependencies = %w(yaml haml hpricot sinatra couchfoo)
block_list %w(couchfoo) # Wait, we don't really want CouchDB!
dependencies.each {|mod| require mod unless block_list.include? mod}
块,闭包,很多东西。我确信早上会出现一些更好的答案,但举个例子,这是我十分钟前写的一些代码 - 我有一组 schedule_collections,其中一些已经发生,其他已经作废、取消等. 我想返回一个只包含待处理的数组。我不确定等效的 Java 是什么,但我想它不是这种单行方法:
def get_all_pending
scheduled_collections.select{ |sc| sc.is_pending? }
end
同样的事情的一个更简单的例子是:
[0,1,2,3].select{|x| x > 1}
这将产生 [2,3]
我喜欢的事
- 更少的代码来表达你的观点
- 传递代码块(Proc,lambdas)很有趣,并且可以产生更小的代码。例如
[1, 2, 3].each{|x| puts "Next element #{x}"}
- 具有 PERL 的脚本根源.. 非常适合分割例程的东西,例如使用正则表达式解析文件等。全部
- Hash 和 Array 等核心数据结构类 API 做得很好。
- 元编程(由于其动态特性) - 创建自定义 DSL 的能力(例如,Rails 可以被称为用 Ruby 编写的 WebApps 的 DSL)
- 为几乎任何事物孕育宝石的社区。
混合。更改 Ruby 类以添加新功能非常简单。
鸭子类型是指类型被认为是由它们实现的方法等价的事实,而不是基于它们声明的类型。举个具体的例子,Ruby 中的许多方法都采用类似 IO 的对象来对流进行操作。这意味着对象必须实现足够多的函数才能作为 IO 类型对象传递(它必须听起来足够像鸭子)。
最后,这意味着您必须编写比 Java 更少的代码来做同样的事情。不过,动态语言的一切都不是很好。您或多或少地放弃了 Java(和其他强/静态类型语言)为您提供的所有编译时类型检查。Ruby 根本不知道您是否将错误的对象传递给方法。这会给你一个运行时错误。此外,在实际调用代码之前,它不会给您一个运行时错误。
只是为了笑,这是语言灵活性的一个相当糟糕的例子:
class Fixnum
def +(other)
self - other
end
end
puts 5 + 3
# => 2