---
title: AstroCamp Ruby 190723
description: 整理筆記
robots: noindex, nofollow
lang: zh-tw
dir: ltr
breaks: true
tags: Ruby
disqus: hackmd
---
{%hackmd BkVfcTxlQ %}
###### 20190723 tags: `Ruby`
# Method
## Block
不要在Block裡使用Return
```ruby=
def say_hi
yield 123
puts "hi"
end
p say_hi{|x|
puts x
return 100
}
#return 交出控制權or結束這回合!!
```
```ruby=
def my_select(list)
result = []
list.each do |y|
if yield(y)
result << y
end
end
return result
end
x = (1..10).to_a
p my_select(x) { |item| item.odd? }
```
>### ==Q.為什麼要使用Block?==
>程式使用起來較有彈性[name=邱宏毅][color=#00cc00]
>## ==Q.Guess what would you get?==
```=ruby
def say
p yield(123)
end
say { |x|
p x
}
```
```=ruby
def say
puts yield(123)
end
say { |x|
p x
}
```
```=ruby
def say
p yield(123)
end
say { |x|
puts x
}
```
```=ruby
def say
puts yield(123)
end
say { |x|
puts x
}
```
>FIFO = First In First Out, Queue
>LIFO = Lasi In First Out, Stack
```ruby=
def hi
hi()
end
hi() # SystemStackError
```
==Block_given==
block不是參數(只是寄生) 的內建防呆
```ruby=
def say_hello
if block_given?
yield
end
end
say_hello #段落呢???
```
## ==Proc==
```=ruby
say_hi = Proc.new { puts "hi" }
say_hi.call
###不要用###
#say_hi.()
#say_hi.[]
#say_hi.===
#say_hi.yield
```
```ruby=
young_people = Proc.new { 18 }
case
when young_people
puts "年輕人"
else
puts "nothing"
end
#年輕人
young_people = Proc.new { 18 }
case
when young_people.=== #自動執行.===
puts "年輕人"
else
puts "nothing"
end
r = 1..10
r.===8 #=> true
r.===11 #=> false
```
>### ==Q.Why Proc?==
>匿名函數的概念[name=邱宏毅][color=#00cc00]
## ==λ lambda==
```ruby=
add_two = lambda { |n| n + 2 }
add_two = -> (n) { n + 2 }
p add_two.call(3)
p add_two[3]
p add_two.(3)
p add_two.===(3)
```
>### ==Q.Proc 和 Lambda 的差別?==
>Lambda 比較像方法,對引數數量上的正確性要求[name=邱宏毅][color=#00cc00]
```ruby=
add_two_proc = Proc.new { |n| n + 2 }
add_two_lambda = lambda { |n| n + 2 }
p add_two_proc.call(1, 2, 3) # 正常執⾏,印出 3
p add_two_lambda.call(1, 2, 3) # 發⽣引數個數錯誤
```
# ==OOP==
>### ==Q.在 Ruby裡什麼不是物件?== ###
>開放作答: 尚未被物件化之前的Block
類別的命名規定 = 必須是常數(大寫)
>ex:A辣
>
## Class
```ruby=
class Cat
def sleep
puts "zzzz"
end
end
kitty = Cat.new
kitty.sleep #zzzz
```
```ruby=
class M60A3
def 發射!
puts "boom!"
end
end
坦克 = M60A3.new
坦克.發射! #boom!
```
### ==繼承 inheritance==
>繼承,更像是在進行分類
```ruby=
class Animal
def walk
end
def eat
end
end
class Dog < Animal
end
class Cat < Animal
end
kitty = Cat.new
kitty.eat
來福 = Dog.new
來福.walk
```
### ==Initialize (初始化)==
```ruby=
class Cat
def initialize(name)
puts "born! I am #{name}"
end
end
kitty = Cat.new("kk") #=> born! I am kk
```
>### new 和 initialize 之間具有先後的關係
```ruby=
class Cat
def initialize(name)
puts "我出生了! 我是 #{name}"
end
end
kitty = Cat.new("kk") #出生了! 我是 kk
```
### ==實體變數(Instance Variable)==
>區域變數是沒有預設值的;
>實體變數的預設值是Nil。
>
>實體變數存在於實體的範圍裡
>實體變數在類別裡可以自由取用
## ==實體方法&類別方法==
```ruby=
class Cat
#instance method
def say
puts "I'm instance method"
end
#class method ,記得加上self
def self.all
puts "I'm class method"
end
end
kitty = Cat.new#使用kitty 產生實體
kitty.say #盡在不言中
Cat.all #盡在不言中
```
>Q.什麼時候需要使用類別方法?為什麼要使用類別方法?
>A.使用上的差異:類別方法更直覺?
>```ruby=
>m = Math.new
>p Math.abs(-10) # 實體方法
>
>p Math.abs(-10) # 類別方法
>
>```
>
==繼承的進階應用:==
```ruby=
class A
def abc
puts "aaa"
end
end
class B < A
def abc
# puts "bbb"
super(abc) # 呼叫class A 的 abc method
end
end
kitty = A.new
p kitty.abc # => "aaa"
```
## ==實體變數與類別變數==
```ruby=
class Cat
def initialize(name)
@name = name
end
#Ruby 並沒有“屬性”的概念,只有方法。
#所以要def 一個 name(),才能正常運作
def name # Getter
@name
end
#Ruby 並沒有“屬性”的概念,只有方法。
#所以要def 一個 name=(),才能正常運作
def name=(new_name) # Setter
@name = new_name
end
end
kitty = Cat.new('kitty')
puts kitty.name # 會印出什麼?
kitty.name = "nancy"
puts kitty.name # 會印出什麼?
```
### ==外部取用實體變數 - Lazy does matter==
```ruby=
class Cat
attr_accessor :name #Getter + Setter
# attr_reader :name #Getter
# attr_writer :name #Setter
def initialize(name)
@name = name
end
def say_my_name
return @name
end
end
kitty = Cat.new('kitty')
puts kitty.say_my_name
puts kitty.name
puts kitty.name= "patty"
```
## ==Class Variable(類別變數)==
```ruby=
class Cat
@@counter = 0
def initialize
@@counter += 1
end
def self.counter #如果沒有加上self. 會出現錯誤
@@counter
end
end
5.times{Cat.new}
p Cat.counter
```
>## ==Q.如果改用實體變數來寫?==
```ruby=
class Cat
def initialize
@counter = 0
end
def go
@counter += 1
end
end
kitty = Cat.new
p kitty.go
p kitty.go
p kitty.go
nancy = Cat.new
p nancy.go
```
### ==兩個同名的類別撞在一起不會覆蓋而是融合==
> Open Class
```ruby=
class Cat
def hello
end
end
class Cat
def world
end
end
kitty= Cat.new
kitty.hello # 會發⽣錯誤?
kitty.world
```
### ==Open Class 對現存的class 也能作用==
```ruby=
class String
def bark
puts %Q("Meow~ saied from #{self})
end
#如果是對現存的方法,則會被覆蓋掉
def length
100
end
end
puts "Dog".bark
puts "Dog".length
```
==Monkey Patching==
```ruby=
class String
def say_hello
"オッス!オラ#{self}"
end
end
puts "悟空".say_hello #=> 印出「オッス!オラ悟空」
```
>Other Example:
```ruby=
#open class 改寫原本預設的方法
class Integer
def +(n)
100
end
end
class Integer
alias :old_plus :+
#利用這種寫法,可以有更具彈性的發揮空間
def +(n)
puts "hey hey hey"
self.old_plus(n)
end
end
puts 1+(2)
puts 2 + 3
```
```ruby=
class Integer
def day
self
end
alias :days :day
def ago
"#{self} days ago"
end
end
p 1.day.ago #1 days ago
p 3.days.ago #3 days ago
```
## ==Public / Private / Protected==
```ruby=
class Cat
def hi
end
private
def gossip
end
end
kitty = Cat.new
kitty.gossip
#testwork.rb:13:in `<main>': private method `gossip' called for
#<Cat:0x00007fb36203b6b0> (NoMethodError)
```
:::info
kitty.say_hello() 在這段程式碼中:
接收者 => kitty
訊息 => say_hello()
對kitty 這個接收者(receiver),發送一個say_hello的訊息(message)
private = 不能有明確的接收者
= 在呼叫方法的時候不會有小數點
protected = 不限定是否有明確的接收者
:::
```=ruby
class Cat
def say
gossip #此時gossip 符合前述,無接收者的要求,可以正常執行
# self.gossip #會出錯
# bark #可正常作用
self.bark #可正常作用
end
private
def gossip
puts "You think you know me."
end
protected
def bark
end
end
kitty = Cat.new
kitty.say
#private is not so private
kitty.send(:gossip)
# gossip #private 無法於外部存取
# bark #protected 無法於外部存取
```