# 認識Ruby
## 印出hello world 的三種方式
#### 方法一:一行終端機指令: (要注意單引號跟雙引號)
$ ruby -e "puts 'hello, world'"
#### 方法二:使用 irb。
#### 方法三:寫在某個檔案裡:
例如VScode檔名是 abc.rb,寫完別忘了存檔!
請 Ruby 來執行它:
$ ruby abc.rb
## 「print」 vs 「puts」 vs 「p」
#### 印出 Hello, World 字樣
```ruby=
print "Hello, World"
```
#### 印出 Hello, World 字樣,並在結尾加上換⾏
```ruby=
puts "Hello, World" # Hello, World
```
#### 印出 "Hello, World" 字樣(含雙引號),並在結尾加上換⾏
```ruby=
p "Hello, World" # "Hello, World"
```
:::info
nil代表不存在
:::
## 註解 Comment 方式
註解不會被執行
在 Ruby 比較常用單行註解
用途:
說明某段程式碼的用途
暫時把某些程式碼「關起來」
#### 方法一
=begin
這是多⾏註解
這裡的內容不會被執⾏
這裡的內容不會被執⾏
這裡的內容不會被執⾏
=end
#### 方法二
#這是單⾏註解
#這裡的內容不會被執⾏
#這裡的內容不會被執⾏
#這裡的內容不會被執⾏
## 變數與常數
a | | = 2 同等 a = a | | 2
如果a的值有設定或是ture就維持原貌,否則給2
---
### 變數練習
x = 2 , y = 3 將兩者資料對調
#### 方法一、暫存變數
```ruby=
x=2
y=3
a=x
x=y
y=a
```
#### 方法二、資料總和扣除
```ruby=
x=2
y=3
x= x+y
y= x-y
x= x-y
```
#### 方法三、 多重指定(ruby專用)
```ruby=
x=2
y=3
x,y = y,x
```
:::warning
在Ruby的世界常數是可以被修改的
:::
---
## 命名慣例
ruby 多用 snale_case
---
## 字串
單引號的字串不會做帶入或翻譯,雙引號的字串會
### 雙引號
```ruby=
name = "kk"
age= 18
puts "hi i am #{name}, i am #{age} years old."
```
result
hi i am kk, i am 18 years old.
### 單引號
```ruby=
puts 'hi i am #{name}, i am #{age} years old.'
```
result
hi i am #{name}, i am #{age} years old.
### 引號不夠用的狀況
舉例
```ruby=
puts 'i'm #{age} years old.'
```
解決方法
方法一、加入跳多字元「\」
```ruby=
puts 'i\'m #{age} years old.'
```
方法二、 用%Q(等同雙引號)或%q(等同單引號)
```ruby=
puts %Q(hi i am #{name}, i'm #{age} years old.)
puts %q(hi i am #{name}, i'm #{age} years old.)
```
result
hi i am kk, i'm 18 years old.
hi i am #{name}, i'm #{age} years old.
---
## 數字 (Ruby:數字其實也是物件)
### 整數
```ruby=
puts 3.55.round #轉成整數,四捨五入
puts 3.74.floor #轉成整數,無條件捨去
puts 3.14.ceil #轉成整數,無條件進位
puts 3.14.to_i #轉成整數,無條件捨去
```
#### 整數除法 (Ruby:整數除以整數會得到整數)
```ruby=
puts 10/3 # 會得到3
```
### 浮點數
要得到小數的話,只要在整入後面給予小數
```ruby=
puts 10.0/3
puts 10/3.0
pust 10.0/3.0
```
---
## 邏輯判斷與流程控制
= => 指定
== => 比對
```ruby=
a=10
b="10"
p a==b #false
```
=== => 比對or其他事情
### 判斷
* Ruby中除了**nil**和**false**是假的,其他都是真的
### if / else
```ruby=
weather = "rain"
if weather == "rain"
puts "stayhome"
else
puts "GoOut"
end
```
#### if 倒裝句
```ruby=
puts "stayhome" if weather == "rain"
```
### unless
unless = if not
if = unless not
#### 寫法一
```ruby=
if not weather == "rain" #不是rain 就 GoOut
puts "GoOut"
end
```
#### 寫法二
```ruby=
unless weather == "rain"
puts "GoOut"
end
```
### unless 倒裝句
```ruby=
puts "GoOut" if not weather == "rain"
puts "GoOut" unless weather == "rain"
```
#### 三元運算子
原本寫法
```ruby=
if age>= 18
status = "adult"
else
status "notadult"
end
```
三元運算子寫法
```ruby=
status = (age>=18) ? "adult" : "notadult"
```
### if.. elsif .. else ..
* 注意不是 else if 是 elsif
```ruby=
weather = "rain"
if weather == "rain"
puts "HOME"
elsif weather == "sunny"
puts "OutDoor"
else
puts "sleep"
end
```
### case .. when .. (Ruby中類似if寫法)
判斷值符合條件
```ruby=
weather = "rain"
case weather
when "rain"
puts "HOME"
when "sunny"
puts "OutDoor"
else
puts "sleep"
end
```
:::info
#### 範圍的shortcut寫法
原本的寫法
```ruby=
age = 10
case age
when age >= 0 && age <=3 # 0-3歲
puts "baby"
when age >= 4 && age <=10 # 4-10歲
puts "child"
when age >= 11 && age <=17 # 11-17歲
puts "teenager"
else
puts "adult"
end
```
shouthand寫法 ( .. => range )
```ruby=
age = 16
case age
when 0..3
puts "baby"
when 4..10
puts "child"
when 11..17
puts "teenager"
else
puts "adult"
end
```
:::
---
## 迴圈與迭代
:::info
差異性
迴圈: 重複做某一件事(跑5圈操場)
迭代: 每件事都做一次(5座操場各跑1次)
:::
### for 迴圈 (概念有點像迭代)
```ruby=
names = ["Amy","John","Tom","Emily"]
for name in names # 每一圈在轉的時候都有變數name可以用
puts name
end
```
### while 迴圈 (邪惡分身: until = while not)
#### while = until not
```ruby=
x = 0
while x < 10
puts x
x +=1 #條件記得,不然會無窮迴圈
end
```
#### while not
```ruby=
x = 0
until x >= 10
puts x
x +=1
end
```
### loop 迴圈
```ruby=
i = 0
loop do
puts i
i+=1
break if i > 10
end
```
:::info
do .. end(Ruby特有寫法) 或 { } 為block的概念
:::
### method 迴圈 (Ruby持有)
#### .times 做幾次
範例
```ruby=
5.times do
puts "hello, ruby"
end
```
#### .upto 向上計數 (從初始值做到設置數值)
範例
```ruby=
1.upto(10) do |i|
puts "counts to #{i}"
end
```
#### .downto 向下計數 (從初始值做到設置數值)
```ruby=
10.downto(1) do |i|
puts "counts to #{i}"
end
```
### 迭代式迴圈 interation (常用)
#### .each
```ruby=
names = ["Amy","John","Tom","Emily"]
names.each do |name|
puts name
end
```
如果想要印出索引值
```ruby=
names = ["Amy","John","Tom","Emily"]
names.each.with_index do |name , x|
puts "#{x} #{name}"
end
```
## 陣列
### 建立方式
方式一 用[]
```ruby=
list = ["ruby","php","python"]
p list #["ruby", "php", "python"]
```
方式二 用%w,且不用逗號跟雙引號 (%w建立出來的會是字串陣列)
```ruby=
list = %w(ruby php python)
p list #["ruby", "php", "python"]
```
### 使用陣列
#### 陣列元素位子
```ruby=
list = %w(ruby php python)
p list[2] # "php"
```
```ruby=
list = %w(ruby php python)
p list[-1] # "python"
```
:::info
從0開始算,若要從後面開始哪從負值
:::
### **first** & **last**
取用第一個元素或最後一個元素
```ruby=
list = %w(ruby php python)
p list.first #ruby
p list.last #python
```
加括號裡面放入值,可以選擇拿前或後x的數值
```ruby=
list = [1,2,3,4,5,6,7,8,9,10]
p list.first(4) #[1, 2, 3, 4]
```
### 印出陣列長度 .lenght
```ruby=
list = %w(ruby php python)
puts list.length #3
```
### 加入新資料到陣列
#### <<
```ruby=
list = %w(ruby php python)
list << %q(Java)
#puts list # ruby php python Java
```
#### 用.push效果一樣
```ruby=
list = %w(ruby php python)
list.push('Java')
puts list
```
### map or collect
對集合裡的每個元素**進行運算**,並收集成一個新的**集合**。
```ruby=
list = [1,2,3,4,5]
p list.map{|x| x*2} #[2, 4, 6, 8, 10]
```
:::warning
這裡不用%w,印為%w輸出會是內容會是字串
:::
```ruby=
list = [1,2,3,4,5]
p list.collect{|x| x*2} #[2, 4, 6, 8, 10]
```
```ruby=
p (1..10).map{|x| x*2}
#[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
```
### select (filter用途)
從集合裡**挑選符合條件**的元素,並收集成一個新的**集合**。
相反: reject 挑選不符合條件
```ruby=
p (1..10).select {|x| x<5}
# [1, 2, 3, 4]
```
```ruby=
p (1..10).reject {|x| x<5}
# [5, 6, 7, 8, 9, 10]
```
### reduce
對集合裡的每個元素**進行運算**,並將所有運算結果歸納成一個**單一結果**
每一圈會將前一次運算完的累加值丟回sum,然後將下一個元素丟入x繼續運算
```ruby=
p (1..10).reduce {|sum, x| sum + x} #55
```
### compact
將陣列中的nil拿掉
```ruby=
list=[1,3,4,1,7,nil,7]
p list.compact #[1,3,4,1,7,7]
```
### sort 排序(小到大)
```ruby=
list=[1,3,4,1,7,nil,7]
p list.compact.sort #[1, 1, 3, 4, 7, 7]
```
### uniq 將陣列中重複的元素拿掉
```ruby=
list=[1,3,4,1,7,nil,7]
p list.compact.sort.uniq #[1, 3, 4, 7]
```
## 範圍
(1..10) 範圍 1 ~ 10
('a'..'z') 範圍 a ~ z
(1...10) 範圍 1 ~ 9
:::success
口訣: 多一點的少一點,少一點的多一點
:::
* .to_a 會將結果轉為陣列
印出1~10
```ruby=
for i in 1..10
puts i
end
```
練習:
印出 1~100 的單數
```ruby=
p (1..100).select{|x| x%2 ==1}
p (1..100).select{|x| x.odd?}
#odd:奇數 ?:詢問 odd?:詢問是否為奇數
```
印出 1~100 的總和
```ruby=
i = (1..100).to_a
p i.reduce{|sum,x| sum+x}
p (1..100).sum # sum為單純計算總合用,結果一樣
```
印出5個小於100且不重複的亂數
* shuffle 隨機打亂排序,
```ruby=
p (1..100).to_a.shuffle.first(5)
```
* simple 從陣列中隨機取樣
```ruby=
p (1..100).to_a.sample(5)
```
---
## Hash
類似字典的概念,key跟value的組合
:::warning
* key跟分號不能有空格
:::
### 建立方式
```ruby=
a = Hash.new
```
或用 b= {} 來建立 (name 為 key ,age 為 value)
```ruby=
b = {name: 'kk', age: 18} #Ruby 1.9之後的新式寫法
```
:::info
舊式寫法
```ruby=
b = {:name => 'kk', :age => 18}
```
:::
#### 取用key的值 (對的key拿到對的value)
```ruby=
b = {name: 'kk', age: 18}
p b[:name] #"kk"
```
#### 印出全部keys跟values的方式
```ruby=
b = { name: 'kk', age: 18}
p b.keys #[:name, :age]
p b.values #["kk", 18]
```
---
## 符號 (symbol)
符號不是個變數,他就是一個值
1 是數字物件,"aa"是字串物件,:hello是符號物件
name = "kk" 全域變數name指定為"kk"
:name = "kk" 語法錯誤,因為兩個都是值
```ruby=
myname = "Mike"
name = :name
```
字串的內容可以變,但符號(Symbol)不行
```ruby=
name = "abcdefg"
name[1] = "x"
p name #axcdefg
```
```ruby=
name = :abcdefg
name[1] = "x"
p name #語法錯誤,符號(Symbol)不能改
```
字串的效能比符號差一點
印出
```ruby=
p "hello".object_id 每次都會給新的記憶體位置
p :hello.object_id 每次都會給同一個記憶體位置
```
:::info
object_id 可以印出這個物件在ruby空間的記憶體位置
:::
冷凍字串
puts "hello".freeze.object_id 固定其記憶體位置
### 字串轉符號
```ruby=
p "name".to_sym #印出:name
p "name".intern #印出:name
```
### 符號轉字串
```ruby=
p :name.to_s #印出name
p :name.id2name #印出name
```
結論: 字串 vs 符號
不可變,選擇符號or冷凍字串
需要組合需要變化,選擇字串