ruby新手的注意事项?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (9)

我最近学习了Ruby编程语言,它是一种很好的语言。但我很地发现,它并不像我想象的那么简单。

x = true and false
puts x  # displays true!

puts "zero is true!" if 0  # zero is true!

提问于
用户回答回答于

维基百科Ruby gotchas

变量与函数的命名规则

乍看之下与Perl的命名规则有些类似,不过Perl的命名用来区分标量、数组与映射;而Ruby的命名规则用来表示变量与类别的关系。Ruby的变量有以下几种:

  • 一般小写字母、下划线开头:变量(Variable)。
  • $开头:全局变量(Global variable)。
  • @开头:实例变量(Instance variable)。
  • @@开头:类变量(Class variable)类别变量被共享在整个继承链中
  • 大写字母开头:常量(Constant)。

有些函数则会加一个后缀,用来表示函数的用法,跟变量命名规则不同,函数的命名规则只是习惯,不具强制性,即使你不照规则命名也不影响程序运作

  • =结尾:赋值方法,相当于其他编程语言的set开头的方法,算是一种语法糖
  • !结尾:破坏性方法,调用这个方法会修改本来的对象,这种方法通常有个非破坏性的版本,调用非破坏性的版本会回传一个对象的副本。
  • ?结尾:表示这个函数的回传值是个布尔值。

多种字符串表示法

Ruby提供了多种字符串的表示方法,方便撰写有大量文字数据的程序。除了来自C语言的引号表示法之外,还有来自于Perl的百分号字面量记法,以及方便书写大量内容的Heredoc记法。Ruby可以方便地以#{variable_name}的方式向字符串中插入变量。

a = '\n这是一个单引号的字符串,反斜线和变量插值不会被转义'

b = %q{这是一个不可转义的字符串}

c = "\n这是一个双引号的字符串,反斜线和变量插值会被转义\n#{a}"

d = %Q{\n這是一個常量字串,特殊内容同样会被转义\n}

e = <<BLOCK
这是一个以Heredoc方式书写的常量字符串,可转义,结尾标志不可缩进
BLOCK

f = <<-BLOCK
      这是一个可以缩进的Heredoc字符串
    BLOCK

g = <<~BLOCK
      这是一个可以缩进的Heredoc字符串
      缩进会被自动去掉,在2.3版本中引入
    BLOCK

h = %/\t这是一个可转义的的字符串\n/

动态修改对象、类别

Ruby是动态语言,你可以在程序中修改先前定义过的类别。 也可以在某个类别的实例中定义该实例特有的方法,这叫做原型方法(prototype)。

class MyClass
  def the_method
    "general method"
  end
end

mc = MyClass.new
def mc.the_method
  "special for this instance."
end

mc.the_method

强大的反射机制与元编程

Ruby的反射功能相当惊人,甚至可以自行追踪程序运作,或是取出private变量、拦截方法的调用。 常常与‘可以动态的修改对象’这项特色结合,做为‘元编程’的功能:程序在运行时, 可以由程序员提供的信息,自行生成、修改类别或对象,这项功能大大的提高了撰写代码的效率。 在Rails之中,就大量使用了这种特性。

以下为用Rails使用元编程的示例:

class Project < ActiveRecord::Base
  belongs_to :portfolio
  has_one    :project_manager
  has_many   :milestones
end

在这个例子中,Project类别继承Base类别,Base类别内置的belongs_tohas_onehas_many方法,便会根据参数来修改Project类别的内容,并自行创建其他相关的方法。程序员可以更专心处理程序的运作,而不必为每个类别重复得撰写代码。

用户回答回答于

a = b = "joe"

a==b       # true
a.eql? b   # true
a.equal? b # true (a.object_id == b.object_id)

a = "joe"
b = "joe"

a==b       # true
a.eql? b   # true
a.equal? b # false (a.object_id != b.object_id)

a = 1
b = 1.0

a==b       # true
a.eql? b   # false (a.class != b.class)
a.equal? b # false

请注意==,,,EQL?equal?应该总是对称的:如果a==b,那么b=a。

还请注意==EQL?在类对象中都实现为equal?

class Person
    attr_reader name
    def == (rhs)
      rhs.name == self.name  # compare person by their name
    end
    def eql? (rhs)
      self == rhs
    end
    # never override the equal? method!
end

# === is usually simply an alias for ==
"joe" === "joe"  # true
"joe" === "bob"  # false

# but ranges match any value they include
(1..10) === 5        # true
(1..10) === 19       # false
(1..10) === (1..10)  # false (the range does not include itself)

# arrays just match equal arrays, but they do not match included values!
[1,2,3] === [1,2,3] # true
[1,2,3] === 2       # false

# classes match their instances and instances of derived classes
String === "joe"   # true
String === 1.5     # false (1.5 is not a String)
String === String  # false (the String class is not itself a String)

case a
  when "joe": puts "1"
  when 1.0  : puts "2"
  when (1..10), (15..20): puts "3"
  else puts "4"
end

if "joe" === a
  puts "1"
elsif 1.0 === a
  puts "2"
elsif (1..10) === a || (15..20) === a
  puts "3"
else
  puts "4"
end

class Subnet
  [...]
  def include? (ip_address_or_subnet)
    [...]
  end
  def === (rhs)
    self.include? rhs
  end
end

case destination_ip
  when white_listed_subnet: puts "the ip belongs to the white-listed subnet"
  when black_listed_subnet: puts "the ip belongs to the black-listed subnet"
  [...]
end

扫码关注云+社区