指定變數
==
一個有趣的問題:
```
a=10
b=15
c=a+b
print(c) #25
a=0
print(c) #25
how to get c 15?
```
要回答這個問題,首先就從最基本的變數指定來看
以 `golang`為例
```go=
a := 10
fmt.Printf("address of a : %v\n", &a)
// address of a : 0xc00002c008
b := 15
fmt.Printf("address of b : %v\n", &b)
// address of b: 0xc00002c050
c := a + b
fmt.Printf("address of c : %v\n", &c)
// address of c : 0xc00002c058
fmt.Printf("value of c : %d\n", c)
// value of c : 25
a = 0
fmt.Printf("value of c : %d\n", c)
// value of c : 25
```
[看結果](https://play.golang.org/p/nDlashBlIfY)
從這邊我們可以看到,`a := 10`這個動作會在記憶體裡指定一個位址(`0xc00002c008`),並將10存放在這個位址,同理,b c 也是ㄧ樣
回頭來看這個問題。
第16行,當 a 這個變數改為0的時候,其實我們做的只是把`0xc00002c008`這個位址的值更改為0,理所當然的,它不可能同時去更動到`0xc00002c058`這個位址的值,因此 c 當然還是維持在 25 不變
那該怎麼印出 `c = 15` 呢?
---
* 範例一
```go=
a := 10
fmt.Printf("address of a : %v\n", &a)
// address of a : 0xc00002c008
b := 15
fmt.Printf("address of b : %v\n", &b)
// address of b : 0xc00002c050
c := func() int {
return a + b
}
fmt.Printf("value of c : %d\n", c())
// value of c : 25
a = 0
fmt.Printf("value of c : %d\n", c())
// value of c : 15
b = 5
fmt.Printf("value of c : %d\n", c())
// value of c : 5
```
[看結果](https://play.golang.org/p/DSho8FtVJJ9)
這邊將 c 指定為一個 function,回傳 `a + b`,這樣一來不管 a b 怎麼改變,c 的回傳值還是可以綁定到 a b 的位址
---
* 範例二
最近工作需要,常常用到「觀察者模式」這個 pattern,所以就簡單設計一個**變數觀察者**的模型如下:
```go=
// 定義觀察者介面
type observer interface {
update(name string, num int)
register(interface{})
}
// 變數觀察者
type variableObserver struct {
variables map[string]int
name string
num int
}
// 更新
func (vo *variableObserver) update(name string, num int) {
vo.variables[name] = num
vo.refresh()
fmt.Printf("%s = %d\n", vo.name, vo.num)
}
// 刷新數值
func (vo *variableObserver) refresh() {
vo.num = 0
for _, n := range vo.variables {
vo.num += n
}
}
// 註冊
func (vo *variableObserver) register(item interface{}) {
v := item.(*variable)
vo.variables[v.name] = v.num
vo.refresh()
}
```
這邊為了簡化架構,所以觀察者介面只定義了`update`和`register`兩個行為,`variableObserver`變數觀察者為實作觀察者介面的物件,所有註冊的變數會存在內部的一個`map`裡,`update`會更新指定的變數並透過`refresh`刷新本身的數值
接著定義**變數**
```go=
// 變數
type variable struct {
name string
num int
observer
}
// 註冊
func (v *variable) register(o observer) {
v.observer = o
o.register(v)
}
// 通知
func (v *variable) notify() {
v.observer.update(v.name, v.num)
}
// 更新
func (v *variable) update(n int) {
v.num = n
fmt.Printf("%s updates to %d\n", v.name, v.num)
v.notify()
}
```
一樣為了簡化,每個變數都只有一個觀察者,透過`register`註冊綁定,並實作`update`更新變數的值,同時通知觀察者同步更新
[看結果](https://play.golang.org/p/vf_5wgRz_wD)
---
這個問題其實很不錯,非常適合拿來和初學者解釋變數和基本型別
延伸閱讀:
[python中的變數](https://openhome.cc/Gossip/Python/Variable.html)
[觀察者模式](https://openhome.cc/Gossip/DesignPattern/ObserverPattern.htm)
[Reactive Programming](https://weihanglo.tw/posts/2017/intro-rx-0-reactivex/)
[Reactivex.io](http://reactivex.io/)