go基础语法备忘录 (一)
Variadic Functions
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
Closures
This function intSeq returns another function, which we define anonymously in the body of intSeq.
func intSeq() func() int {
i := 0
return func() int {
i++
return i
}
}
func main(){
nextInt := intSeq()
fmt.Println(nextInt())
}
Structs
Go’s structs are typed collections of fields. They’re useful for grouping data together to form records.
type person struct {
name string
age int
}
fmt.Println(person{name: "Alice", age: 30})
s := person{name: "Sean", age: 50}
sp := &s
fmt.Println(sp.age)
Methods
Go supports methods defined on struct types.
type rect struct {
width, height int
}
func (r *rect) area() int {
return r.width * r.height
}
Interface
Interfaces are named collections of method signatures.
To implement an interface in Go, we just need to implement all the methods in the interface.
type geometry interface {
area() float64
perim() float64
}
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
Error
errors.New constructs a basic error value with the given error message.
func f1(arg int) (int, error) {
if arg == 42 {
return -1, errors.New("can't work with 42")
}
return arg + 3, nil
}
It’s possible to use custom types as errors by implementing the Error() method on them.
type argError struct {
arg int
prob string
}
func (e *argError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
Goroutines
A goroutine is a lightweight thread of execution.(轻量级的进程)
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
go f("goroutine")
start a goroutine for an anonymous function call.
go func(msg string) {
fmt.Println(msg)
}("going")
Channels
Channels are the pipes that connect concurrent goroutines. You can send values into channels from one goroutine and receive those values into another goroutine.
Create a new channel with make(chan val-type)
messages := make(chan string)
Send a value into a channel using the channel <- syntax.
go func() { messages <- "ping" }()
The <-channel syntax receives a value from the channel.
msg := <-messages
fmt.Println(msg)
Channel Buffering
By default channels are unbuffered, meaning that they will only accept sends (chan <-) if there is a corresponding receive (<- chan) ready to receive the sent value. Buffered channels accept a limited number of values without a corresponding receiver for those values.
Here we make a channel of strings buffering up to 2 values.
messages := make(chan string, 2)
Because this channel is buffered, we can send these values into the channel without a corresponding concurrent receive.
messages <- "buffered"
messages <- "channel"
Later we can receive these two values as usual.
fmt.Println(<-messages)
fmt.Println(<-messages)
Channel Synchronization
Here’s an example of using a blocking receive to wait for a goroutine to finish.
If you removed the <- done line from this program, the program would exit before the worker even started.
func worker(done chan bool) {
fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println("done")
done <- true //Send a value to notify that we’re done.
}
func main() {
done := make(chan bool, 1) //Start a worker goroutine, giving it the channel to notify on.
go worker(done)
<-done //Block until we receive a notification from the worker on the channel.
}
Channel Directions
When using channels as function parameters, you can specify if a channel is meant to only send or receive values. This specificity increases the type-safety of the program.
Run code
This ping function only accepts a channel for sending values. It would be a compile-time error to try to receive on this channel.
func ping(pings chan<- string, msg string) {
pings <- msg
}
The pong function accepts one channel for receives (pings) and a second for sends (pongs).
func pong(pings <-chan string, pongs chan<- string) {
msg := <-pings
pongs <- msg
}
func main() {
pings := make(chan string, 1)
pongs := make(chan string, 1)
ping(pings, "passed message")
pong(pings, pongs)
fmt.Println(<-pongs)
}