Skip to content
gqlxj1987's Blog
Go back

Go101

Edit page

原文链接

value parts

The main characteristic of C types is the memory layouts of their values are transparent

Go can also be viewed as C language framework. This is mainly reflected in the fact that Go supports several kinds of types whose value memory layouts are not totally transparent. Each values of the these kinds of types is often composed of one direct part and one or several underlying indirect parts, and the underlying value part is referenced by the direct value part

Two kinds points

Internal Definitions of the types

// map types
type _map *hashtableImpl // currently, for the standard Go compiler,
                         // Go maps are hashtables actually.

// channel types
type _channel *channelImpl

// function types
type _function *functionImpl

// slice types
type _slice struct {
	elements unsafe.Pointer // underlying elements
	len      int            // number of elements
	cap      int            // capacity
}

// string types
type _string struct {
	elements *byte // underlying bytes
	len      int   // number of bytes
}

// general interface types
type _interface struct {
	dynamicTypeInfo *struct {
		dynamicType *_type       // the dynamic type
		methods     []*_function // implemented methods
	}
	dynamicValue unsafe.Pointer // the dynamic value
}

underlying value parts are not copied in value assignments

In Go, each value assignment (including parameter passing, etc) is a shallow value copy if the involved destination and source values have the same type (if their types are different, we can think that the source value will be implicitly converted to the destination type before doing that assignment). In other words, only the direct part of the soruce value is copied to the destination value in an value assignment. If the source value has underlying value part(s), then the direct parts of the destination and source values will reference the same underlying value part(s), in other words, the destination and source values will share the same underlying value part(s).

Here I just list some absolutely misuses of reference

line break rules in go

One rule we often obey in practice is, we should not put the a starting curly brace ({) of the explicit code block of a control flow block on a new line.

for i := 5; i > 0; i-- {
}

However, there are some exceptions for the rule mentioned above. For example, the following bare for loop block compiles okay.

for
{
	// do something ...
}

活用;

Some Panic/Recover Use Cases

avoid panics crashing programs

package main

import "errors"
import "log"
import "net"

func main() {
	listener, err := net.Listen("tcp", ":12345")
	if err != nil {
		log.Fatalln(err)
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
		}
		// Handle each client connection in a new goroutine.
		go ClientHandler(conn)
	}
}

func ClientHandler(c net.Conn) {
	defer func() {
		if v := recover(); v != nil {
			log.Println("client handler panic:", v)
		}
		c.Close()
	}()
	panic(errors.New("just a demo.")) // a demo-purpose panic
}

automatically restart a crash goroutine

package main

import "log"
import "time"

func shouldNotExit() {
	for {
		time.Sleep(time.Second) // simulate a workload
		// Simultate an unexpected panic.
		if time.Now().UnixNano() & 0x3 == 0 {
			panic("unexpected situation")
		}
	}
}

func NeverExit(name string, f func()) {
	defer func() {
		if v := recover(); v != nil { // a panic is detected.
			log.Println(name, "is crashed. Restart it now.")
			go NeverExit(name, f) // restart
		}
	}()
	f()
}

func main() {
	log.SetFlags(0)
	go NeverExit("job#A", shouldNotExit)
	go NeverExit("job#B", shouldNotExit)
	select{} // blocks here for ever
}

use panic/recover to reduce error checkings

package main

import "fmt"

func doTask(n int) {
	if n%2 != 0 {
		// Create a demo-purpose panic.
		panic(fmt.Errorf("bad number: %v", n))
	}
	return
}

func doSomething() (err error) {
	defer func() {
		// The ok return must be present here, otherwise,
		// a panic will be created if no errors occur.
		err, _ = recover().(error)
	}()

	doTask(22)
	doTask(98)
	doTask(100)
	doTask(53)
	return nil
}

func main() {
	fmt.Println(doSomething()) // bad number: 53
}

close channel

One general principle of using Go channels is don’t close a channel from the receiver side and don’t close a channel if the channel has multiple concurrent senders. In other words, you should only close a channel in a sender goroutine if the sender is the only sender of the channel.


Edit page
Share this post on:

Previous Post
GAN Example on Keras
Next Post
Flipkart Data Platform