package main import ( "fmt" "time" ) const ( FIRST = "WHAT THE" SECOND = "F*CK" ) funcmain() { var s string gofunc() { i := 1 for { i = 1 - i if i == 0 { s = FIRST } else { s = SECOND } time.Sleep(10) } }() for { if s == "WHAT" { panic(s) } fmt.Println(s) time.Sleep(10) } }
goroutine 1 [running]: main.main() /Users/zerun.dong/code/gotest/string.go:26 +0x11a exit status 2
上面代码运行后,注定要 panic, 代码的主观意愿是字符串赋值是原子的,要么是 F*CK, 要么是 WHAT THE, 为什么会出现 WHAT 呢?
1 2 3 4 5 6 7 8 9 10
// StringHeader is the runtime representation of a string. // It cannot be used safely or portably and its representation may // change in a later release. // Moreover, the Data field is not sufficient to guarantee the data // it references will not be garbage collected, so programs must keep // a separate, correctly typed pointer to the underlying data. type StringHeader struct { Data uintptr Len int }
package main import ( "fmt" "github.com/myteksi/hystrix-go/hystrix" "time" ) var FIRST error = hystrix.CircuitError{Message:"timeout"} var SECOND error = nil funcmain() { var err error gofunc() { i := 1 for { i = 1 - i if i == 0 { err = FIRST } else { err = SECOND } time.Sleep(10) } }() for { if err != nil { fmt.Println(err.Error()) } time.Sleep(10) } }
复现 case 其实是一样的
1 2 3 4 5 6 7 8 9 10
ITCN000312-MAC:gotest zerun.dong$ go run panic.go hystrix: timeout panic: value method github.com/myteksi/hystrix-go/hystrix.CircuitError.Error called using nil *CircuitError pointer
// 没有方法的interface type eface struct { _type *_type data unsafe.Pointer } // 有方法的interface type iface struct { tab *itab data unsafe.Pointer }
道理是一模一样的,只要存在并发读写,就会出现所谓的 partial write
看看 rust
1 2 3 4 5 6 7
fnmain() { let a = String::from("abc"); let b = a;
println!("{}", b); println!("{}", a); }
这是一段 rust 入门级代码,运行会报错:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
ITCN000312-MAC:hello zerun.dong$ cargo run Compiling hello v0.1.0 (/Users/zerun.dong/projects/hello) error[E0382]: borrow of moved value: `a` --> src/main.rs:6:20 | 2 | let a = String::from("abc"); | - move occurs because `a` has type `String`, which does not implement the `Copy` trait 3 | let b = a; | - value moved here ... 6 | println!("{}", a); | ^ value borrowed here after move
error: aborting due to previous error
因为变量 a 己经被 move 走了,所以程序不可以再继续使用该变量。这就是 rust ownership 所有权的概念。在编译器层面就避免了上面提到的问题,当然 rust 学习曲线太陡。