English 中文(简体)
通用的 Ruby 成语
原标题:
  • 时间:2009-03-05 08:35:51
  •  标签:

我喜欢 Ruby 的一个地方是它大部分都是一种易读的语言(这对于自我记录代码非常有用)。

However, inspired by this question: Ruby Code explained and the description of how ||= works in ruby, I was thinking about the ruby idioms I don t use, as frankly, I don t fully grok them.

所以我的问题是,类似于引用问题中的示例,作为一个真正熟练的Ruby程序员,我需要了解哪些常见但不明显的Ruby习语?

顺便说一下,来自所提到的问题

a ||= b 

等同于

if a == nil || a == false
  a = b
end

感谢Ian Terrell的纠正。

编辑:事实证明,这一点并非完全没有争议。事实上,正确的扩展是……

(a || (a = (b))) 

请参考这些链接,了解原因:

感谢Jörg W Mittag指出此事。

最佳回答

让同一个文件可以作为库或脚本使用的魔法if从句:

if __FILE__ == $0
  # this library may be run as a standalone script
end

打包和解包数组:

# put the first two words in a and b and the rest in arr
a,b,*arr = *%w{a dog was following me, but then he decided to chase bob}
# this holds for method definitions to
def catall(first, *rest)
  rest.map { |word| first + word }
end
catall(  franken ,  stein ,  berry ,  sense  ) #=> [  frankenstein ,  frankenberry ,  frankensense  ]

哈希作为方法参数的语法糖

this(:is => :the, :same => :as)
this({:is => :the, :same => :as})

哈希初始化函数:

# this
animals = Hash.new { [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {}
# is not the same as this
animals = Hash.new { |_animals, type| _animals[type] = [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]}

元类语法

x = Array.new
y = Array.new
class << x
  # this acts like a class definition, but only applies to x
  def custom_method
     :pow
  end
end
x.custom_method #=> :pow
y.custom_method # raises NoMethodError

类实例变量 (lè shí lì bìng biàn liàng)

class Ticket
  @remaining = 3
  def self.new
    if @remaining > 0
      @remaining -= 1
      super
    else
      "IOU"
    end
  end
end
Ticket.new #=> Ticket
Ticket.new #=> Ticket
Ticket.new #=> Ticket
Ticket.new #=> "IOU"

块,procs和lambda。活着并深入研究他们。

 # know how to pack them into an object
 block = lambda { |e| puts e }
 # unpack them for a method
 %w{ and then what? }.each(&block)
 # create them as needed
 %w{ I saw a ghost! }.each { |w| puts w.upcase }
 # and from the method side, how to call them
 def ok
   yield :ok
 end
 # or pack them into a block to give to someone else
 def ok_dokey_ok(&block)
    ok(&block)
    block[:dokey] # same as block.call(:dokey)
    ok(&block)
 end
 # know where the parentheses go when a method takes arguments and a block.
 %w{ a bunch of words }.inject(0) { |size,w| size + 1 } #=> 4
 pusher = lambda { |array, word| array.unshift(word) }
 %w{ eat more fish }.inject([], &pusher) #=> [ fish ,  more ,  eat  ]
问题回答

这个幻灯片演示文稿包括了主要的 Ruby 习语,十分完整。

  • 交换两个值:

    x, y = y, x 交换x和y的值。

  • 如果没有指定的参数会采用默认值。

    def somemethod(x, y=nil)的中文翻译为:def somemethod(x, y=nil)

  • 批处理将外部参数打包成数组

    def substitute(re, str, *rest) 翻译成中文: def substitute(re, str, *rest)

等等...

一些更多的成语:

使用%w%r%(分隔符

%w{ An array of strings %}
%r{ ^http:// }
%{ I don t care if the string has  single  or "double" strings }

在情况语句中的类型比较

def something(x)
  case x
    when Array
      # Do something with array
    when String
      # Do something with string
    else
      # You should really teach your objects how to  quack , don t you?
  end
end

在案例语句中滥用 === 方法

case x
  when  something concrete  then ...
  when SomeClass then ...
  when /matches this/ then ...
  when (10...20) then ...
  when some_condition >= some_value then ...
  else ...
end

对Ruby程序员而言,这应该是很自然的事,但对于来自其他编程语言的人来说可能并不是这样:使用each代替for..in

some_iterable_object.each{|item| ... }

在Ruby 1.9+,Rails中,或者通过修补Symbol#to_proc方法,这种方法越来越流行:

strings.map(&:upcase)

条件方法/常量定义

SOME_CONSTANT = "value" unless defined?(SOME_CONSTANT)

查询方法和破坏性(bang)方法

def is_awesome?
  # Return some state of the object, usually a boolean
end

def make_awesome!
  # Modify the state of the object
end

隐式展开参数

[[1, 2], [3, 4], [5, 6]].each{ |first, second| puts "(#{first}, #{second})" }

我喜欢这个。

str = "Something evil this way comes!"
regexp = /(w[aeiou])/

str[regexp, 1] # <- This

这是(大致)相当于:

str_match = str.match(regexp)
str_match[1] unless str_match.nil?

或者至少我用这个来替换这种阻碍。

我建议阅读那些你敬重和欣赏的人所设计的流行且做得很好的插件或珠宝代码。

我遇到的一些例子:

if params[:controller] ==  discussions  or params[:controller] ==  account 
  # do something here
end

相应的

if [ account ,  discussions ].include? params[:controller]
  # do something here
end

稍后会进行重构

if ALLOWED_CONTROLLERS.include? params[:controller]
  # do something here
end

By the way, from the referenced question

a ||= b 

等于 (děngyú)

if a == nil   
  a = b 
end

那是微妙的不正确,并且是新手Ruby应用程序中错误的来源。

由于nilfalse都只能计算为布尔值假,因此a ||= b实际上(几乎)等价于:

if a == nil || a == false
  a = b
end

或者,用另一种 Ruby 习语进行重写:

a = b unless a

由于每个语句都有一个值,它们在技术上不等同于 a ||= b。但是,如果你不依赖于语句的值,你就看不出区别来。

这里有一些选自不同来源的例子:

使用“除非”和“直到”代替“如果不”和“当不”。但是,如果存在“else”条件,请尽量不要使用“除非”。

记住你可以同时分配多个变量:

a,b,c = 1,2,3

甚至可以不使用临时变量交换变量:

a,b = b,a

在适当的情况下使用尾部条件语句,例如

do_something_interesting unless want_to_be_bored?

要注意一种常用但不立即明显(至少对我而言)的定义类方法的方式:

class Animal
  class<<self
    def class_method
      puts "call me using Animal.class_method"
    end
  end
end

一些参考资料:

我维护一个维基页面,涵盖了一些 Ruby 的惯用语和格式。

将此翻译成中文:https://github.com/tokland/tokland/wiki/RubyIdioms https://github.com/tokland/tokland/wiki/RubyIdioms

我总是忘记这个简写如果否则语句的确切语法(以及运算符的名称。评论了吗?)我认为它在 Ruby 之外被广泛使用,但以防其他人需要语法,这里是它的语法:

refactor < 3 ? puts("No need to refactor YET") : puts("You need to refactor this into a  method")

扩张到

if refactor < 3
  puts("No need to refactor YET")
else
  puts("You need to refactor this into a  method")
end

更新

被称为三元运算符:

返回 myvar ? myvar.size : 0

好问题!

我认为代码越直观和快速,我们构建的软件就越好。我将展示我如何使用Ruby以小片段的代码来表达我的想法。 在此处阅读更多

Map

我们可以以不同的方式使用map方法:

user_ids = users.map { |user| user.id }

或者:

user_ids = users.map(&:id)

样品 (yàng pǐn)

我们可以使用随机方法:

[1, 2, 3][rand(3)]

洗牌

[1, 2, 3].shuffle.first

而通俗、简单和最容易的方式是……样品!

[1, 2, 3].sample

双管等于符号/记忆化

正如你在描述中所说,我们可以使用记忆化:

some_variable ||= 10
puts some_variable # => 10

some_variable ||= 99
puts some_variable # => 10

静态方法 / 类方法

我喜欢使用类方法,我认为这是创建和使用类的非常惯用的方式:

GetSearchResult.call(params)

Simple. Beautiful. Intuitive. What happens in the background?

class GetSearchResult
  def self.call(params)
    new(params).call
  end

  def initialize(params)
    @params = params
  end

  def call
    # ... your code here ...
  end
end

了解如何编写通俗易懂的 Ruby 代码,阅读这里

您可以轻松使用 Marshaling 对象进行深复制。

def deepcopy(o)
  Marshal.load(Marshal.dump(o))
end

Note that files and I/O streams, as well as Method and Binding objects, are too dynamic to be marshaled; there would be no reliable way to restore their state.

a = (b && b.attribute) || "default"

大致上是:

if ( ! b.nil? && ! b == false) && ( ! b.attribute.nil? && ! b.attribute.false) a = b
else a = "default"

当b是可能已经被找到或未被找到的记录,并且我需要获取其中一个属性时,我使用此内容。

我喜欢如何通过返回值缩短 If-then-else 或 case-when。

if test>0
  result = "positive"
elsif test==0
  result = "zero"
else
  result = "negative"
end

可以重写。

result = if test>0
  "positive"
elsif test==0
  "zero"
else
  "negative"
end

同样的方法也可以应用于case-when:

result = case test
when test>0 ; "positive"
when test==0 ; "zero"
else "negative"
end

Array.pack和String.unpack用于处理二进制文件:

# extracts four binary sint32s to four Integers in an Array
data.unpack("iiii") 

方法缺失 神奇

class Dummy  
  def method_missing(m, *args, &block)  
    "You just called method with name #{m} and arguments- #{args}"  
  end  
end

Dummy.new.anything(10, 20)
=> "You just called method with name anything and arguments- [10, 20]"

如果您调用Ruby对象中不存在的方法,Ruby解释器将调用名为method_missing的方法(如果已定义),您可以将其用于某些技巧,例如编写API包装器或DSL,其中您不知道所有的方法和参数名称。 如果您调用Ruby对象中不存在的方法,Ruby解释器将调用名为method_missing的方法(如果已定义),您可以将其用于某些技巧,例如编写API包装器或DSL,其中您不知道所有的方法和参数名称。





相关问题