iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 3
0
Modern Web

關於 Ruby on Rails,我想說的是系列 第 3

[Day 3] Ruby 常數與變數四兄弟(上)

  • 分享至 

  • xImage
  •  

常數

Ruby 常數是大寫字母開頭,一個值不太需要改變,我們就會把他指定給常數。像是類別跟模組的名稱不會改變就用常數

class Sky
end

module Cloud
end

常數乍聽之下是不能改變,像是JavaScript宣告一個常數,就不能再指定另一個值給他
JS的範例如下:

const num = 1
num = 2    // Uncaught TypeError: Assignment to constant variable.

回到 Ruby

Ruby 的常數是可以改變的

當我用常數Weapon裝備了倚天劍,如果改裝備屠龍刀就會出現警告:

Weapon = '倚天劍'
Weapon = '屠龍刀' # warning: already initialized constant Weapon

出現warning了,但還是可以把屠龍刀指定給帶有倚天劍常數Weapon
這就是Ruby很有彈性的一點,連常數都可以變。
(誰說拿劍就不能改拿刀,刀狂劍癡葉小釵不就都拿了)

常數要從後面插入字串也可以

Weapon = '倚天劍'
Weapon << '屠龍刀' 
Weapon # => "倚天劍屠龍刀" 

如果真的不想要這個常數被插入而改變,可以使用#freeze方法

Weapon = '倚天劍'.freeze
Weapon << '屠龍刀' # FrozenError (can't modify frozen String)

出現FrozenError了,就代表你不能修改已經凍結的字串

freeze有兩個好處:
1.要改變Weapon變得困難
2.字串倚天劍被 cache 住了,之後每次呼叫倚天劍都會從記憶體相同的位置拿出,而不是每用一次倚天劍,就要新增一個記憶體位置(object_id)。

常數介紹完,該換變數豪情四兄弟登場/images/emoticon/emoticon12.gif


Ruby 的變數有4種:區域變數,實體變數,類別變數,全域變數。

昨天提到 Ruby 的區域變數,,而Ruby總共有四種變數,長相不一樣,有效範圍也不同,請聽我娓娓道來:

區域變數 Local Variable

區域變數小弟,顧名思義就是變數的有效範圍只在一個小區域裡,開頭最普通,沒有 @, @@ 或 $

首先我們定義一個read方法,並呼叫他

def read
  novel = '神鵰俠侶'
  p "最愛武俠小說#{novel}"
end

read    # => "最愛武俠小說神鵰俠侶"

p "最愛武俠小說#{novel}" # => NameError (undefined local variable or method `novel' for main:Object)

噴錯了,找不到區域變數novel,因為novel區域變數在定義read方法的區塊之外就拿不到。所以如果一個區域變數被定義在方法的 block 裡面,一出去那個 block ,區域變數就等於是消失了。

如果在 block 外定義novel呢?

novel = '神鵰俠侶'
def read
  p "最愛武俠小說#{novel}"
end

p "最愛武俠小說#{novel}" # => "最愛武俠小說神鵰俠侶"

read    # => NameError (undefined local variable or method `novel' for main:Object)

呼叫 read 方法噴錯了,這樣也是找不到區域變數novel
因為區域變數是由方法 block 所切割,如法呼叫在在方法外的區域變數
ps. #{} 是在雙引號中帶入變數的方法

實體變數 Instance Variable

實體變數三弟,開頭帶有@,存在實體中。
範例如下:
先定義一個ComicBook class

class ComicBook
  def initialize(name)
   @name = name
  end
  
  def read
    p "熱血漫畫:#{@name}"
  end
end

再由 ComicBook產生兩個實體

comic1 = ComicBook.new('排球少年')
# => #<ComicBook:0x00007f8e4a98adc0 @name="排球少年"> 

comic2 = ComicBook.new('棋靈王')
# => #<ComicBook:0x00007f8e4a9783a0 @name="棋靈王"> 

comic1.read   # => "熱血漫畫:排球少年"

comic2.read   # => "熱血漫畫:棋靈王" 

p "熱血漫畫:#{@name}" # => "熱血漫畫:"

上面例子,先產生一個實體 comic1,從#<ComicBook:0x00007f8e4a98adc0 @name="排球少年">可以看到 comic1 帶有 class 名稱 ComicBook,且含有實體變數跟對應的內容@name="排球少年"。 comic1 可以透過read方法印出身上的@name

然後再產生第二個實體,一樣帶有 class 名稱 ComicBook,但是實體變數跟對應的內容不一樣了@name="棋靈王",透過read方法印出的結果也不一樣。

實體變數,是可以被實體隨身攜帶。同一個實體之內,可以跨越不同的 method 而被使用。像是範例中產生 @name的方法是initialize,但是read一樣可以拿到@name

雖然 comic2 也把參數"棋靈王"指定給@name,但是comic1.read依然是印出"排球少年",而不是"棋靈王",代表不同實體之間,就算實體變數名稱相同,也是各自獨立的個體。

最後一行可以看到,因為實體變數的有效範圍就是實體本身,在實體外面想印出@name,只會回傳實體變數的預設值 nil

以上可以知道實體變數三弟有效範圍比區域變數小弟弟更大 (好像哪裡怪怪的)

大哥全域變數,二哥類別變數,請待下回分曉


上一篇
[Day 2] 動態型別語言 Ruby
下一篇
[Day 4]Ruby 常數與變數四兄弟(下)
系列文
關於 Ruby on Rails,我想說的是23
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言