Ruby 10 个 Ruby 技巧提升你的代码

jyootai · 2015年03月30日 · 最后由 iwetuan 回复于 2018年07月23日 · 12188 次阅读
本帖已被管理员设置为精华贴

这里向你展示 10 个 Ruby 技巧(或许你都知道),但不管怎样,这些都是值得分享的东西,并且只需要一点时间就能浏览完。

1.构造 Hash

你可以用一个列表一系列的值构造 Hash 通过 Hash[...] 方法,它将会像下面的方式创建一个 Hash:

Hash['key1', 'value1', 'key2', 'value2']
# => {"key1" => "value1", "key2" => "value"}

2.Lambda 字面量->

定义一个 lambda 可以使用在 Rails 中也用的比较流行的 -> 字面量,它可以很容易的定义一个 lambda 对象

a = -> {1 + 1}
a.call
# => 2

a = ->(arg) {arg + 1}  # 含参
a.call(2)  # 传递参数
# => 3

3.双星 **

双星在 Ruby 中是一个小魔法,来看看下面的方法:

def my_method(a, *b, **c)

end

a 是一个常规的参数,b 将会得到第一个参数后面的所有参数并把他们放入一个数组中, **c 将会得到传人方法的任何格式为 key: value 的参数。

来看看下面的例子:一个参数

my_method(1)
# => [1, [], {}]

超过一个参数

my_method(1, 2, 3, 4)
# => [1, [2, 3, 4], {}]

超过一个参数 + hash-style 参数

my_method(1, 2, 3, 4, a: 1, b: 2)
# => [1, [2, 3, 4], {:a => 1, :b => 2}]

4.操作单个对象和数组用同样的方式

有时你可能会先给出一个选项去接受单个对象或者一个数组对象,而不是最后去检查你接受到对象的类型,这时你可以用 [*type]或者 Array(type)

我们先设置两个变量,第一个是单对象,第二个是数字数组:

obj  = 1
obj_arr = [1, 2, 3]

在下面的例子,通过任何被给定的对象用 [*...] 去循环:

[*obj].each { |s| s }  # => [1]
[*obj_arr].each { |s| s } # => [1, 2, 3]

和上面效果一样,这次用 Array(...)

Array(stuff).each { |s| s } # => [1]
Array(stuff_arr).each { |s| s } # => [1, 2, 3]

5. ||= 操作符号

利用 ||= 操作符能写出很简洁的代码

它实际上和下面的表示方式相同:

a || a = b # 正确

大多数人都认为它和下面的表示方式一样,但实际不是:

a = a || b # 错误

因为如果 a 已经存在,第二种方法的表示就是再给 a 进行分配赋值,但这样其实是没有意义的。

6.强制的哈希参数

这个是在 Ruby 2.0 被引进的,你可以在定义方法时指定接受的参数为 hash 类型,像这样:

def my_method({})
end

你可以指定想要接受值的键,或者为键指定一个默认的值。下面的 a 和 b 是指定要接受值的键:

def my_method(a:, b:, c: 'default')
  return a, b, c
end

我们不给 b 传值来调用它,这时会报错:

my_method(a: 1)
# => ArgumentError: missing keyword: b

由于 c 有一个默认的值,我们可以仅仅只给 a 和 b 传值:

my_method(a: 1, b: 2)
# => [1, 2, "default"]

或者是给所有键传值:

my_method(a: 1, b: 2, c: 3)
# => [1, 2, 3]

我们大多时候的做法是直接传入一个 hash,这样的做法只是看起来更明显,就像下面的方式:

hash = { a: 1, b: 2, c: 3 }
my_method(hash)
# => [1, 2, 3]

7.生成字符或者字符数组

你可能想要生成一个数字列表或者把所有的字符放入一个数组,你可以用 Ruby 的 range 去做这样的事。

A 到 Z:

('a'..'z').to_a
# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

1 到 10:

(1..10).to_a
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

8. Tap

tap 是一个很好的小方法去提高代码的可读性,我们拿下面的类作为例子:

class User
  attr_accessor :a, :b, :c
end

现在去实例化一个对象并为对象的属性去赋值,你可能会这么做:

def my_method
  o = User.new
  o.a = 1
  o.b = 2
  o.c = 3
  o
end

或者你可以用tap使用下面的方式去做:

def my_method
  User.new.tap do |o|
    o.a = 1
    o.b = 2
    o.c = 3
  end
end

基本上,tap 方法引入被调用的对象到代码块中并最后返回它。

9.Hash 默认的值

默认的,当我们试图接受一个在 hash 中未定义的值,你将会得到 nil。但你可以改变这个结果在进行初始化时。 (提示:一般不要这样做除非你知道自己在干什么)

在第一个例子中,我们定义了一个默认的值为 0,所以当我们 a[:a] 时会得到 0 而不是 nil:

a = Hash.new(0)
a[:a]
# => 0

我们能够传入任何形式类型到 Hash 初始函数中:

a = Hash.new({})
a[:a]
# => {}

或者是一个字符串:

a = Hash.new('lolcat')
a[:a]
# => "lolcat"

10. here 文档

here 文档有一个缺点就是它会影响代码流畅和缩进问题,由于 HERE 会缩进两格,但有时为了最后内容连续性,你可能会把每行内容都靠左写,像这样:

def my_method <<-HERE Ruby stricks Interesting Right HERE end 这有一个技巧可以避免它,通过用 gsub 方法加一个正则表达式。你可以自动的去除前面的空格,这样你就能保持缩进。

def my_method
  <<-HERE.gsub(/^\s+/, '')
    Ruby
    stricks
    Interesting
    Right
  HERE
end

出处: http://samurails.com/ruby/ruby-tricks-improve-code/#comment-112866

4.操作单个对象和数组用同样的方式

这玩意在解析 XML 的时候太有用了。。。我现在还是笨笨的 if var.is_a? Array。。。。。。。。。

  1. ||= 不等同于 a || a = b ruby a || a = 2 # NameError: undefined local variable or method `a' for main:Object a ||= 2 # returns 2

多个 heredoc 和别的东西放一行

foo_bar_baz = <<-FOO, <<-BAR, "baz"
foo
FOO
bar
BAR

涨姿势

这些都算语法糖吧?

谢谢分享 涨姿势

a = -> (arg) {arg + 1}
# 调用时也有点糖
a.(2)  # => 3 

#1 楼 @est to_a 比以上方法更易懂,如果确定后来代码只处理数组的话

#9 楼 @shatle 没法用 to_a 吧。。。

某变量 v 为 1 或者为 [1,2,3] v.to_a 会出错的。

3.双星 **

Cool

heredoc 一般啥时候用啊?

#12 楼 @lithium4010 1,向一个对象中动态添加方法 2,向其它文件添加多行内容 3,输出多行结果 ...... 其实 HEREDOC 本质就是为了方便操作多行字符串,具体的使用方法你可以参照 Ruby Heredoc 部分

<<HERE 与<<-HERE 的区别:前者结束符 HERE 必须顶格写,不能有缩进,后者没有这个限制,但 HERE 也必须单独一行 (不能有其它非空白字符)

Rails 里面用strip_heredoc就行了

<<-HEREDOC.strip_heredoc
  blabla
HEREDOC
16 楼 已删除

不认为 tap 增加了可读性

#17 楼 @neverlandxy_naix 减少了中间变量 o,还是有一定作用。

object 作数组这个很实用!

对于 4 如果操作的是一个 Hash,结果会是下面的样子:

[*{k: 1}]
# => [ [:k, 1] ]

#21 楼 @fbsender 是的,小心 Array(obj) 有坑:obj 是个 Hash 的时候,可能不是期望的结果

其实这些东西,遇到需要的时候能想起来才是最重要的吧...大概....

对于第 9 条,Hash 的默认值这个,有一个坑,在构造数组的哈析的时候,

hash_of_array = Hash.new([])
hash_of_array['a'] << "abc"
pp hash_of_array['b'] # => "abc

即每个 key 共用同一个 array。

正确的写法应该是:

hash_of_array = Hash.new {|h,k|  h[k] = Array.new}

"a ||= b"的正确展开式应该为: if defined?(a) then (a || a = b) else a = b end

分享的东西 跟原文有点出入。不过 确实是个好东西。

torvaldsdb 2.0 double splat (**) 的一些用法 提及了此话题。 03月02日 16:23

@serco 短路运算符 要定义

liukai 回复

挖坟?不知道你想表达什么,我已经回复了两个不一样

收藏起来,很不错!

需要 登录 后方可回复, 如果你还没有账号请 注册新账号