Ruby 小白总结:在使用 Ruby 发现一些较为巧妙的写法

Canmel · 2016年12月27日 · 最后由 crazyphage 回复于 2018年07月23日 · 4509 次阅读
user = User.new

设定默认值

user.name ||= '默认值'

防止空指针

| 使用

area = Area.new
user.area = area
user.area&.area_name

| 使用delegate

delegate :area_name, to: :area, allow_nil: true

目标:使用 format 格式化 user.balance,但为0时,为0,而不格式化

| user.balance = 23.027

user.balance.to_i.zero? ? format(‘%.2f’, user.balance) # to_i 可以防止空指针

捕获异常

使用rescue => ex 代替rescue StandardError => ex rescue => ex # 默认捕获StandardError, 推荐一般捕捉StandardError

if...else...end 可以直接返回值

test = ''
if user.balance.to_i.zero?
  test = 'if值'
else
  test = 'else值'
end 

||

test = if user.balance.to_i.zero?
             'if值'
          else
             'else值'
          end

事务

ActiveRecord::Base.transaction do => transaction do

数组处理

user1 = User.new
user2 = User.new

| 目标:获取用户 user 的 id 数组 我之前的写法是这样的

user_id_array = []
[user1, user2].each do |user|
   user_id_array << user1.id
end

||

user_id_array = [user1, user2].map(&:id)   # map() 提取数组某元素,组合成新的数组

字符串处理

| 变量和字符串的拼接 | user.name = '中国'

> ’我爱你‘ + user.name
> “我爱你中国”

||

> "我爱你#{user.name}"
> “我爱你中国”

有什么错误的还请各位前辈指出,有更为精美的代码还希望能给出一点,3q

user_id_array = []
[user1, user2].inject(user_id_array) {|arr, user| arr << user.id; arr} 

还可以这样肛

#1 楼 @matrixbirds 哈,确实是哈,我没用过 inject ,感觉这方法逻辑好奇葩😅

#2 楼 @Canmel hhh 我应该写 reduce 这样就不奇葩了。。

user_id_array = User.ids

#4 楼 @crazyphage 这是查询所有用户 id 的集合吧

user.area&.area_name 这个是新版本里的用法吧

#6 楼 @realwol 空的话就使用&短路掉前面的,至于新与旧,我接触 ruby 时间不长,所以我也不知道这个新旧问题😜

#7 楼 @Canmel 2.3 以前可以用 active_support 里的 try,之前 rubymine 没有更新以前老是提示语法错误,还是用回了 try

#8 楼 @adamshen 不知道是不是我这个是简写的原因呢?在一个方法中想吃掉这个方法中所有的代码块的话能省掉

def xxx
  user.name
rescue => ex
  p 'xxxx'
end

相当于

def xxx
begin
  user.name
rescue => ex
  p 'xxx'
end

捕获 StandardError 是很糟的做法,用异常来代替流程就更糟。其他的或多或少都有些毛病。先多看多学吧,至少把主要 API 和 style guide 过一遍。不着急总结,更不着急分享。

#10 楼 @billy 好的,谢谢 @billy 的意见, 😏 但是我们公司老大是说的要推荐捕获 StandardError,可能是我没有考虑清楚他的用意吧!但是有一点我可能与你持有相反的态度,之前几年我是开发 java 的,因为公司需要,已经‘转行’一年了,看 API,学习语言 style 固然重要,但是闭门造车不是什么褒义词,出来分享的话,第一点是想巩固下之前所学,第二点是这里有很多大神在这个圈子,几个人就有几个风格,如果有大方出手指点一番也未尝不是好事。但是还是谢谢你的建议😀

这个不是仅仅短路,他是新版本里的简写

#12 楼 @realwol 哦哦,不知道是从哪个版本开始的呢?

#13 楼 @Canmel 他这个方法是 a.present? && a.name.present? 这样的简写。版本的话是跟 rails5 一起的 >2.3 吧。

  1. Markdown 的语法还是要学习一下,参考:https://www.zybuluo.com/mdeditor
  2. 相比较遗留代码中的 rescue Exception => e , rescue StandardError => e 稍好一些,所以我推荐先改成 rescue => e. 更好地做法,参考 Effective Ruby 中异常那一节。
  3. user.balance.to_i.zero? ? format(‘%.2f’, user.balance) 这个写法有点奇怪,你再思考一下

@Canmel 童鞋是 Java 转过来的,我刚刚开始带,大家多多鼓励~

#15 楼 @42thcoder 是的!😜 user.balance.to_i.zero? ? format(‘%.2f’, user.balance)这句是有点怪,是这个样子的:我之前可能比较关注的是在 to_i 那一块,这本来是个三目运算,后边我不是很关注他,就去掉了,贴过来感觉多余了😅

变量和字符串的拼接

> ['我爱你', user.name].join
> ['我爱你', user.name] * ''
> '我爱你' << user.name
> '我爱你'.concat(user.name)
> format('我爱你%s', user.name)
> '我爱你%s' % user.name
.......

还有其他的一些方法,当然执行效率是有差别的,也有些是 rubocop 不建议使用的,这里就不啰嗦了

其中,array#*(arg) 这个要复杂些,可以看下源码及 DOC(http://ruby-doc.org/core-2.4.0/Array.html#method-i-2A)

#17 楼 @zfjoy520 rubocop 是指哪种,新手求问

#9 楼 @Canmel 可以直接

def xxx
rescue #可选
ensure #可选 不管是否发生异常是否捕获异常都会执行 (finally)
end

不过你写的相当于的那个形式少了一个 end, 因为给了 begin,rescue 就跟着 begin 了,begin 和 def 各自有一个 end

说到单独用 ensure 有个套路 (可能用不到但会读到)

def foo  #不希望出现在异常回溯(backtrace)中的方法,如就是简单封装另一个方法bar
   bar
ensure
   $@.shift if $@ # $@是异常回溯的数组或nil(无异常发生),移除掉第一项(含有foo的这一项)
end
Canmel 回复

user_id_array = User.where(abc: 'abc').ids

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