iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 29
0
自我挑戰組

Ruby on Rails 與它們相關的東西系列 第 29

Day29 - Ruby 中的 Struct 與 OpenStruct

  • 分享至 

  • xImage
  •  

前言

Ruby 是物件化非常徹底的程式語言,幾乎所有東西都是物件 (除了 block 外),
很常使用 class 來實現物件導向,但每次都要寫 class xxx 建立新的類別挺麻煩的,這時可以使用 StructOpenStruct


OpenStruct

比 Struct 更有彈性, 可以任意增加 Attribute,不像 Struct 需先定義好有哪些 Attribute,無法定義 method,相對效能會較差些

OpenStruct 的祖先分別是

irb

# 在 irb 中,使用 OpenStruct 需 require 'ostruct'
require 'ostruct'
OpenStruct.ancestors
# [OpenStruct, Object, Kernel, BasicObject]

如何使用

# 在 irb 中,使用 OpenStruct 需 require 'ostruct'
require 'ostruct'

# 方法1
Book = OpenStruct.new
Book.class    # OpenStruct
Book.name = 'Ruby on Rails 與它們相關的東西'
Book.url = 'https://riverye.com/'
Book.price = 999
Book.isbn = '987-654-321-0'
Book          #<OpenStruct name="Ruby on Rails 與它們相關的東西", url="https://riverye.com/", price=999, isbn="987-654-321-0">

Book.name     # Ruby on Rails 與它們相關的東西'
Book[:name]   # Ruby on Rails 與它們相關的東西'
Book['name']  # Ruby on Rails 與它們相關的東西'


# 方法2
Book = OpenStruct.new(name: 'Ruby on Rails 與它們相關的東西', isbn: '987-654-321-0')
Book.name     # Ruby on Rails 與它們相關的東西'
Book[:name]   # Ruby on Rails 與它們相關的東西'
Book['name']  # Ruby on Rails 與它們相關的東西'
Book.name = '小菜'
Book.price = 999
Book.name     # 小菜
Book[:name]   # 小菜
Book['name']  # 小菜

刪除某一個元素

Book
#<OpenStruct name="小菜", isbn="987-654-321-0", price=999, hello=13>

Book.delete_field(:price)
#<OpenStruct name="小菜", isbn="987-654-321-0", hello=13>

Struct

使用前,需先定義好 Attribute,不像 OpenStruct 那麼彈性(較嚴謹),但可以定義方法 (method) ,相對效能較好些

Struct 的祖先分別是

Book = Struct.new(:name)
Book.ancestors
[#<Class:0x00007fa7ee9bb048>, Struct, Enumerable, Object, Kernel, BasicObject]

如何使用

# 在 irb 中可直接使用
Book = Struct.new(:name, :price, :url, :isbn)
book_1 = Book.new('Ruby on Rails 與它們相關的東西', 999, 'https://riverye.com/', '987-654-321-0')

需要照順序放 Attribute 喔,若不想照順序放 Attribute 的話,可使用 keyword_init: true

Book = Struct.new(:name, :price, :url, :isbn, keyword_init: true)
book_hash = { url: 'https://riverye.com/', isbn: '987-654-321-0', name: 'Ruby on Rails 與它們相關的東西', price: 999}
book_1 = Book.new(book_hash)
#<Struct:Book:0x00000168
  # isbn = "987-654-321-0",
  # name = "Ruby on Rails 與它們相關的東西",
  # price = 999,
  # url = "https://riverye.com/"

Struct 可以定義方法

Book = Struct.new('Book', :price) do
  def over_thousand?
    price >= 1000
  end
end

Book.new(1000).over_thousand?
# true

Struct 比較嚴謹

Book = Struct.new(:name, :url)

# 未帶入的變數會自動變成 nil
book_1 = Book.new('Ruby on Rails 與它們相關的東西')
book_1.name # 'Ruby on Rails 與它們相關的東西'
book_1.url  # nil

# 無法隨時新增屬性
Book.tatal = 1
# NoMethodError (undefined method `total=' for Book:Class)

# 宣告時帶入太多參數會產生錯誤,比 OpenStruct 嚴謹許多
book_1 = Book.new('Ruby on Rails 與它們相關的東西', isbn: '987-654-321-0')
# ArgumentError (struct size differs)

OpenStruct VS. Struct 比較

效能上兩者差異蠻大的,可參考 Stack Overflow 這篇,個人也是比較常用 Struct

參考資料

  1. Ruby -- Struct v.s openStruct
  2. 模擬class物件:Ruby當中Struct及OpenStruct的使用
  3. Ruby - Struct vs OpenStruct
  4. OpenStruct in Ruby
  5. 关于ruby:何时应该使用Struct vs. OpenStruct?

小結

個人蠻常在測試中使用,像是要要測試 Sidekiq 的 Sidekiq::RetrySet.new,使用 Struct 來模擬,挺方便的,也會用在不同地方,下一篇會是鐵人賽總結(終於~~


鐵人賽文章連結:https://ithelp.ithome.com.tw/articles/10249081
medium 文章連結:https://link.medium.com/YGEc5Qnqjab
本文同步發布於 小菜的 Blog https://riverye.com/

備註:之後文章修改更新,以個人部落格為主


上一篇
Day28 - Ruby on Rails 中串 Slack 服務
下一篇
Day30 - 不免俗一定要來一下的完賽心得
系列文
Ruby on Rails 與它們相關的東西31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言