-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
golang #28
Comments
Call by Value & Call by Referencearray & slice 參數 注意事項
func main() {
ary := [1]int{}
fmt.Println("main", ary, fmt.Sprintf("%p", &ary))
test(ary)
fmt.Println("main", ary, fmt.Sprintf("%p", &ary))
}
func test(a [1]int) {
a[0] = 1
fmt.Println("test", a, fmt.Sprintf("%p", &a))
}
/*
main [0] 0xc000018030
test [1] 0xc000018038
main [0] 0xc000018030
*/ 可以看到傳入 func 的 array 記憶體位址改變了 同樣的情況放到 slice 就稍微有點不同: func main() {
slice := []int{}
fmt.Println("main", slice, fmt.Sprintf("%p", &slice))
test(slice)
fmt.Println("main", slice, fmt.Sprintf("%p", &slice))
}
func test(s []int) {
s[0] = 1
fmt.Println("test", s, fmt.Sprintf("%p", &s))
}
/*
main [0] 0xc00000c030
test [1] 0xc00000c048
main [1] 0xc00000c030
*/ 一樣可以發現傳進去的 slice 記憶體位址改變了, 雖然副本 slice 可以操作同一個 array, func main() {
slice := []int{0}
fmt.Println("main", slice, fmt.Sprintf("%p", &slice))
test(slice)
fmt.Println("main", slice, fmt.Sprintf("%p", &slice))
}
func test(s []int) {
s = append(s, 1)
fmt.Println("test", s, fmt.Sprintf("%p", &s))
}
/*
main [0] 0xc00000c030
test [0 1] 0xc00000c060
main [0] 0xc00000c030
*/ slice 還沒超過 cap 時,你操作 slice 等於影響原始資料 array; 為何建構函式要使用 pointerA: Go 是一個 pass by value 的程式語言,也就是每當我們把值放入函式中時,Go 會把這個值完整的複製一份,並放到新的記憶體位址https://pjchender.dev/golang/pointers/ func main() {
q := new(hp)
q.name = "kevin"
fmt.Println(q.name) // kevin
q.rename1("ben")
fmt.Println(q.name) // kevin
q.rename2("ben")
fmt.Println(q.name) // ben
}
type hp struct {
name string
}
func (h hp) rename1(n string) {
h.name = n
}
func (h *hp) rename2(n string) {
h.name = n
} |
new(), T{}, &T{} 差別func main() {
q1 := new(hp)
fmt.Println(unsafe.Sizeof(q1)) // 8
q2 := hp{}
fmt.Println(unsafe.Sizeof(q2)) // 16
name := ""
fmt.Println(unsafe.Sizeof(name)) // 16
q3 := &hp{}
fmt.Println(unsafe.Sizeof(q3)) // 8
}
type hp struct {
name string
} |
go channel 關閉的那些事兒https://juejin.cn/post/7033671944587182087 什麼情況下關閉 channel 會造成 panic ?
// 1.未初始化時關閉
func TestCloseNilChan(t *testing.T) {
var errCh chan error
close(errCh)
// Output:
// panic: close of nil channel
}
// 2.重複關閉
func TestRepeatClosingChan(t *testing.T) {
errCh := make(chan error)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
close(errCh)
close(errCh)
}()
wg.Wait()
// Output:
// panic: close of closed channel
}
// 3.關閉後傳送
func TestSendOnClosingChan(t *testing.T) {
errCh := make(chan error)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
close(errCh)
errCh <- errors.New("chan error")
}()
wg.Wait()
// Output:
// panic: send on closed channel
}
// 4.傳送時關閉
func TestCloseOnSendingToChan(t *testing.T) {
errCh := make(chan error)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
defer close(errCh)
go func() {
errCh <- errors.New("chan error") // 由於 chan 沒有緩衝佇列,程式碼會一直在此處阻塞
}()
time.Sleep(time.Second) // 等待向 errCh 傳送資料
}()
wg.Wait()
// Output:
// panic: send on closed channel
} Q: go channel 關閉後,讀取該 channel 會?A: 永遠不會阻塞,且只會輸出對應類型的零值。func TestReadFromClosedChan(t *testing.T) {
var errCh = make(chan error)
go func() {
defer close(errCh)
errCh <- errors.New("chan error")
}()
go func() {
for i := 0; i < 3; i++ {
fmt.Println(i, <-errCh)
}
}()
time.Sleep(time.Second)
// Output:
// 0 chan error
// 1 <nil>
// 2 <nil>
} |
Golang 中 Channel 对阻塞 goroutine 的唤醒顺序分析https://blog.csdn.net/shida_csdn/article/details/88344017 Q: 當 Channel 可用時,它是按照什麼順序喚醒等待的 goroutine 協程的呢?A: 先阻塞的先被喚醒!多個 goroutine 等待讀取 ch,雖然誰先呼叫讀取是不確定的, |
Golang 的 GC學習Go 垃圾回收
STW(Stop-The-World)觸發的時間一次GC有兩次觸發STW,一次是GC的開始階段,主要是開啟寫屏障和輔助GC等操作 另外就是表記完成之後,重新掃描部分根對象,停用寫屏障 Go 什麼時候會觸發 GC?
1. 系統觸發:執行階段自行根據內建的條件,檢查、發現到,則進行 GC 處理,維護整個應用程式的可用性。
2. 手動觸發:開發者在業務程式碼中自行呼叫 runtime.GC 方法來觸發 GC 行為。在手動觸發的場景下,Go 語言中僅有 runtime.GC 方法可以觸發,也就沒什麼額外的分類的。 三色標記的過程
|
deferdefer 是延遲執行,可以將其後面的程式碼延後至函式結束時執行。Defer 可以 stack,執行順序先進後出 func main() {
fmt.Println("defer begin")
defer fmt.Println("Hello World")
defer fmt.Println("Hey World")
defer fmt.Println("Hi World")
fmt.Println("defer end")
}
/* print out:
defer begin
defer end
Hi World
Hey World
Hello World
*/ recoverrecover 可捕捉系統自動產生或手動設定產生的 panic 錯誤,回復系統以避免程序崩潰。recover 必須和 defer 配合使用!recover 必須和 defer 配合使用!recover 必須和 defer 配合使用!(很重要) package main
import "fmt"
func main() {
fmt.Println("Taiwan: Here Comes 2021")
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
fmt.Println("Don't panic! We got vaccinated!")
}
fmt.Println("Life still moves on!")
}()
panic("Oh! No! COVID Pandemic!")
} |
Goroutine 與 Thread 比較
程式 (Program)、進程 (Process)、線程 (Thread)、協程 (coroutine/goroutine)GPM
Scheduler原理以及查看Goroutine执行 |
golang面試題整理
slice & channel 的底层原理和注意事项
常規性Golang面試題解析
Go 實現常用設計模式
Go 易錯面試題彙總 (code)
type assertion
sync
匿名函數語閉包
Go semaphore
The text was updated successfully, but these errors were encountered: