---
# System prepended metadata

title: Ruby(02/14) Day 27 五倍紅寶石(第八屆共筆)(2021/8/03)
tags: [Ruby]

---

# Ruby(02/14) Day 27 五倍紅寶石(第八屆共筆)(2021/8/03)
## id
所有物件都有 id ，可用 .object_id 來找。

## Symbol 符號
- 有名字的物件
- id 固定，不能修改值
- 原本用完記憶體不會歸還 (Memory Leak)，新版 Ruby 用完會還
- 因為 id 固定，查找、比較的速度比字串還快
- 本身就是值，不能拿來當變數用

a = :aaa
a 是變數，aaa 是名字為 aaa 的物件，他本身就是值，不能拿來當變數用。
literal: 字面上的意思，蘋果標誌就是、[]、{}也是。

- :xxx.to_s:符號轉字串

最後一個引數如果是 hash，{}可省略不寫。
![](https://i.imgur.com/pOgCBcK.png)


## String 字串
- 是字串物件
- id 不固定、可以修改他的值：連續 puts "aaa".object_id ，會得到不同的 id ，因為字串存放的記憶體位置都不同，用 .freeze 可固定記憶體
- 用完記憶體會歸還
- 可用方法較符號多
- 本身就是值，不能拿來當變數用

符號跟字串都是一個抽象類別，在上層定義方法給下層用，比較不佔記憶體。

ex: 
假設我的抽象類別有50個忍術可以用
在讀取的時候只要讀取一次抽象類別
下層就可以直接用了
整個環境只會有50個忍術

如果不這樣做的話
我每次下層新建立一個忍者就要塞50個忍術給他
建立50個忍者就會有2500個忍術跑出來
而且還是重複的，很吃記憶體

- "xxx".to_sym:字串轉符號

## 數字
- 是數字物件
- id 固定，不能修改值
- 本身就是值，不能拿來當變數用

## 模組化
把別的檔案的內容加進來用。
- require
  - ()、副檔名可省略不寫 
  - 寫多次 require 只會載入一次內容
  require("./b.rb") => 執行./b.rb 這個檔案，所有內容都會執行
  require "json" => 找 json 這個套件來用，不是找這個檔案

- load
  - ()可省略不寫，副檔名不能省
  - 寫多次 load 會載入多次內容
  - live server 就是這樣，本地開發用(當我修改完會立即更新)

## Rake
用來寫各種任務的，把他濃縮成一行指令，可以快速在 Rails 建好東西。
不是 Rack
= Ruby 版的 make
拆成很多 task，像是模組化的概念。

用法：
- 先做一個檔名是 rakefile 的檔案!!!
- 裡面寫 task end，task 名稱要用符號，手冊寫的!
- desc 用來幫他加描述
- rake + 方法名稱可執行
- rake -T 可查看目前檔案內有哪些任務，有寫描述的才看的到
- namespace 可用來做分類(類似類別)，避免撞名且較清楚
```=rb
# 用 task 方法定義方法名稱 foo，讓我們可以使用
# desc 用來幫他加描述(註解)
namespace:db do
  desc:"foo方法"
  task :foo do
    puts "bar" 
  end
end

# 呼叫 db 裡面的 foo 方法，這邊的:不是符號，是冒號的意思，是終端機的指令，用來找內層的東西
rake db:foo 

# 預設任務
task :default do
  puts ...
end

# 指定預設任務是 db:foo
task :default => "db:foo"

# 先後順序：會先做 => 後面的任務，上廁所前要先開門
task :go_to_toliet do
  puts "上廁所"
end

task :go_to_toliet => open_door do
  puts "開門"
end
```

## Block
- 沒辦法單獨存活，可寄生在別的方法後面
- 是一段不會被主動執行的程式碼
- 會自動回傳最後一行的執行結果
- LocalJumpError
  - 用 return，會出錯，新版 Ruby 不會跑出錯誤訊息，會在 return 那邊停住
  - 有用 yield 但沒寫 {} 也會出錯
- 不是參數，()內的才是
- 看到他就知道前面一定有個方法，讓我可以執行
- block_given? 
  可以判斷是否為 block

有兩種型態：
1. do end
結合率較弱，有多行通常會用 do end
2. {}
結合率較強，只有一行通常會用{}

- yield
  - 用來執行 block 內的程式碼
  - yield 後面沒值的話會印出 nil
  - 沒寫 |n| 讓 yield 帶值進來會跑出 NameError，找不到 n

```=rb
# 印出
# Hello, 你好 
# there!
# 會跳過 here，因為沒有用 yield

def say_hello
  puts "Hello, 你好"
end
say_hello {
  puts "here!"
}
puts "there!"



# 印出
# Hello, 你好
# yield 轉移控制權到下面的 block
# here!
# 轉移控制權回到 yield 之後
# Hello, ⼤大家好
# there!

def say_hello
  puts "Hello, 你好"
yield
  puts "Hello, ⼤大家好"
end
say_hello {
  puts "here!"
}
puts "there!"



# 轉讓控制權時，會帶 3 跟 8 給 block
# 印出 3、8

def say_hello
  yield 3, 8
end
say_hello do |n, m|
  puts n
  puts m
end
```

```=rb
# i 的值是從 times 方法 yield 出來的
5.times do |i|
```

```=rb
# block 會自動回傳最後一行的執行結果
# 把 3 當引數傳到 n ，回傳 false，走到 else

def test_two
  if yield(3)
    puts "yes, it is 2"
  else
    puts "no, it is not 2"
  end
end
test_two { |n|
  n == 2
}
```

## Proc 類別
可以把 block 變成可被呼叫物件，讓他能單獨存在
可用 call 呼叫他
```=rb
a= Proc.new {|n| n*2}
p a.call(2)
Proc.new 可用 lambda 代替
lambda 可簡寫成：
-> (n) {n + 2}
```

---

###### tags: `Ruby`
