[www.liwenzhou.com/][https://w…]

Golang Chinese document address: studygolang.com/pkgdoc

Basic Syntax of Go language (Medium)

1. Introduction to FMT standard library

The FMT package implements formatted I/O similar to the C languages printf and scanf. It is mainly divided into two parts: output content and input content.

1.1 Output

The standard library FMT provides the following output related functions.

1.1.1 Print

Print will Print the content to the system’s standard output. The difference is that Print will Print the content directly, Printf will format the output string, and Println will add a newline at the end of the output.

func Print(a ...interface{}) (n int, err error)
func Printf(format string, a ...interface{}) (n int, err error)
func Println(a ...interface{}) (n int, err error)
Copy the code

Here’s a simple example:

func main(a) {
	fmt.Print("Print this information at the terminal.")
	name := "The Little Prince of Sand River"
	fmt.Printf("I am: %s\n", name)
	fmt.Println("Print a single line at the terminal for display.")}Copy the code

Execute the code output above:

The information is printed on the terminal. I am: Sand river little prince in the terminal to print a separate line displayCopy the code

1.1.2 Fprint

The Fprint series of functions will print the content to a variable w of type IO.Writer interface. We usually use this function to write content to a file.

func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
Copy the code

Here’s an example:

// Write to standard output
fmt.Fprintln(os.Stdout, "Write to standard output")
fileObj, err := os.OpenFile("./xx.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
iferr ! =nil {
	fmt.Println("Error opening file, err:", err)
	return
}
name := "The Little Prince of Sand River"
// Write to an open file handle
fmt.Fprintf(fileObj, "Write to file as message: %s", name)
Copy the code

Note that any type that satisfies the IO.Writer interface supports writing.

1.1.3 Sprint

The Sprint series of functions generates and returns a string from the incoming data.

func Sprint(a ...interface{}) string
func Sprintf(format string, a ...interface{}) string
func Sprintln(a ...interface{}) string
Copy the code

Simple example code is as follows:

s1 := fmt.Sprint("The Little Prince of Sand River")
name := "The Little Prince of Sand River"
age := 18
s2 := fmt.Sprintf("name:%s,age:%d", name, age)
fmt.Println(s2)
s3 := fmt.Sprintln("The Little Prince of Sand River")
fmt.Println(s1, s2, s3)
Copy the code

1.1.4 Errorf

The Errorf function generates a formatted string from the format argument and returns an error containing the string.

func Errorf(format string, a ...interface{}) error
Copy the code

This is often used to customize error types, for example:

err := fmt.Errorf("This is a mistake.")
Copy the code

Go1.13 added a %w placeholder for fmt.Errorf to generate a Wrapping Error.

e := errors.New("Original error E")
w := fmt.Errorf("Wrap an error %w", e)
Copy the code

1.2 Formatting placeholders

* The printf family of functions all support the format format parameter, here we are divided by the type of variable placeholder will be replaced, easy to query and memory.

1.2.1 Universal placeholders

A placeholder instructions
%v The default format representation of the value
%+v Similar to %v, except that the field name is added to the output structure
%#v The Go syntax representation of the value
%T The type of the printed value
% % percent

Example code is as follows:

fmt.Printf("%v\n".100)
fmt.Printf("%v\n".false)
o := struct{ name string} {"The Little Prince"}
fmt.Printf("%v\n", o)
fmt.Printf("%#v\n", o)
fmt.Printf("%T\n", o)
fmt.Printf("100%%\n")
Copy the code

The following output is displayed:

100
falseStruct {name string}{name:"The Little Prince"}
struct { name string }
100%
Copy the code

1.2.2 the Boolean

A placeholder instructions
%t True or false

1.2.3 integer

A placeholder instructions
%b Expressed as binary
%c The unicode code value corresponding to this value
%d Expressed as decimal
%o Represented as octal
%x The value is in hexadecimal format, using a to F
%X The value is in hexadecimal format, using A to F
%U Unicode format: U+1234, equivalent to “U+%04X”
%q The value corresponds to a single quoted go syntax character literal, safely escaped when necessary

Example code is as follows:

n := 65
fmt.Printf("%b\n", n)
fmt.Printf("%c\n", n)
fmt.Printf("%d\n", n)
fmt.Printf("%o\n", n)
fmt.Printf("%x\n", n)
fmt.Printf("%X\n", n)
Copy the code

The following output is displayed:

1000001
A
65
101
41
41
Copy the code

1.2.4 Floating point and complex numbers

A placeholder instructions
%b A scientific notation without decimal parts or binary exponents, such as -123456p-78
%e Scientific counting method, such as -1234.456e+78
%E Scientific counting method, such as -1234.456e +78
%f There is a fractional part but no exponential part, e.g. 123.456
%F Equivalent to the % f
%g Use % E or % F format depending on the situation (for cleaner, more accurate output)
%G Use %E or %F format depending on the situation (for cleaner, more accurate output)

Example code is as follows:

f := 12.34
fmt.Printf("%b\n", f)
fmt.Printf("%e\n", f)
fmt.Printf("%E\n", f)
fmt.Printf("%f\n", f)
fmt.Printf("%g\n", f)
fmt.Printf("%G\n", f)
Copy the code

The following output is displayed:

6946802425218990p-49
1.234000e+01
1.234000E+01
12.340000
12.34
12.34
Copy the code

1.2.5 Characters and byte []

A placeholder instructions
%s Output a string or []byte
%q The value corresponds to a double-quoted GO syntax string literal, safely escaped when necessary
%x Each byte is represented by a two-character hexadecimal number (using a-f
%X Each byte is represented as A two-character hexadecimal number (using a-f)

Example code is as follows:

s := "The Little Prince"
fmt.Printf("%s\n", s)
fmt.Printf("%q\n", s)
fmt.Printf("%x\n", s)
fmt.Printf("%X\n", s)
Copy the code

The following output is displayed:

The little prince"The Little Prince"
e5b08fe78e8be5ad90
E5B08FE78E8BE5AD90
Copy the code

1.2.6 pointer

A placeholder instructions
%p Represented in hexadecimal, plus a leading 0x

Example code is as follows:

a := 10
fmt.Printf("%p\n", &a)
fmt.Printf("%#p\n", &a)
Copy the code

The following output is displayed:

0xc000094000
c000094000
Copy the code

1.2.7 Width identifiers

The width is specified by a decimal number immediately following the percent sign, and if the width is not specified, the value is represented without padding beyond what is required. Precision is specified by the (optional) width followed by a dot number followed by a decimal number. If no precision is specified, the default precision is used. If the dot is not followed by a number, the precision is 0. Examples are as follows:

A placeholder instructions
%f Default width, default precision
%9f Width 9, default accuracy
%.2f Default width, precision 2
% 9.2 f Width 9, accuracy 2
%9.f Width 9, accuracy 0

Example code is as follows:

n := 12.34
fmt.Printf("%f\n", n)
fmt.Printf("%9f\n", n)
fmt.Printf("%.2f\n", n)
fmt.Printf("% 9.2 f \ n", n)
fmt.Printf("%9.f\n", n)
Copy the code

The following output is displayed:

12.340000
12.340000
12.34
    12.34
       12
Copy the code

Other falg 1.2.8

A placeholder instructions
‘+’ Always output the value of the plus or minus sign; For %q (%+q) output is all ASCII characters (by escaping);
‘ ‘ Log values, positive numbers are preceded by a space and negative numbers by a negative sign; Using %x or %x for strings (%x or %x) adds a space between each printed byte
‘-‘ Fill the right side of the output with white space instead of the default left (that is, switch from the default right to left);
‘#’ Octal numbers are preceded by 0 (%#o), hexadecimal numbers by 0x (%#x) or 0x (%#x), Pointers to remove the preceding 0x (%#p) pairs of %q (%#q), and %U (%#U) prints a space and a single quoted go literal;
‘0’ Use zeros instead of Spaces for padding, and place zeros after signs for numeric types;

Here’s an example:

s := "The Little Prince"
fmt.Printf("%s\n", s)
fmt.Printf("%5s\n", s)
fmt.Printf("%-5s\n", s)
fmt.Printf("% s \ n" 5.7, s)
fmt.Printf("- 5.7% s \ n", s)
fmt.Printf("% s \ n" 5.2, s)
fmt.Printf("%05s\n", s)
Copy the code

The following output is displayed:

Little prince little prince Little prince little prince 00 Little princeCopy the code

1.3 Obtaining Input

The FMT package of Go language has three functions, FMT.Scan, FMT.Scanf and FMT.Scanln, which can obtain user input from standard input during program running.

1.3.1 FMT. Scan

The signature of the function is as follows:

func Scan(a ...interface{}) (n int, err error)
Copy the code
  • Scan scans text from standard input, reading values separated by whitespace characters and saving them to arguments passed to the function, with newlines treated as whitespace characters.
  • This function returns the number of successfully scanned data and any errors encountered. If the number of data read is less than the parameter provided, an error report is returned.

Specific code examples are as follows:

func main(a) {
	var (
		name    string
		age     int
		married bool
	)
	fmt.Scan(&name, &age, &married)
	fmt.Printf("Scan result Name :%s age:%d married:%t \n", name, age, married)
}
Copy the code

Compile the above code and execute it on the terminal. Enter little prince, 28, and false on the terminal, separated by Spaces.

$./scan_demo Little Prince 28falseName: Young prince age:28 Married:false 
Copy the code

Fmt.scan scans user input data from standard input and stores whitespace separated data to specified parameters.

1.3.2 FMT. The Scanf

The function signature is as follows:

func Scanf(format string, a ...interface{}) (n int, err error)
Copy the code
  • Scanf scans text from standard input, reading whitespace delimited values in the format specified by the format argument and saving them to arguments passed to the function.
  • This function returns the number of successfully scanned data and any errors encountered.

A code example is as follows:

func main(a) {
	var (
		name    string
		age     int
		married bool
	)
	fmt.Scanf("1:%s 2:%d 3:%t", &name, &age, &married)
	fmt.Printf("Scan result Name :%s age:%d married:%t \n", name, age, married)
}
Copy the code

Compile the above code and run it on the terminal, where you enter prince, 28, and false in the specified format.

$./scan_demo 1: Little Prince 2: 283 3:falseName: Young prince age:28 Married:false 
Copy the code

Scanf is different from FMT.Scan, which simply uses Spaces as delimiters for input data. FMT.Scanf specifies a specific input format for the input data. Only the input format is scanned and stored in corresponding variables.

For example, if we continue to type in the whitespace delimited way we did in the previous example, FMT.Scanf will not scan the entered data correctly.

$./scan_demo Little Prince 28falseName: age:0 Married:false 
Copy the code

1.3.3 FMT. Scanln

The function signature is as follows:

func Scanln(a ...interface{}) (n int, err error)
Copy the code
  • Scanln is similar to Scan in that it stops scanning only when a newline is encountered. The last data must be followed by a line break or end position.
  • This function returns the number of successfully scanned data and any errors encountered.

Specific code examples are as follows:

func main(a) {
	var (
		name    string
		age     int
		married bool
	)
	fmt.Scanln(&name, &age, &married)
	fmt.Printf("Scan result Name :%s age:%d married:%t \n", name, age, married)
}
Copy the code

Compile the above code and execute it on the terminal. Enter little prince, 28, and false on the terminal, separated by Spaces.

$./scan_demo Little Prince 28falseName: Young prince age:28 Married:false 
Copy the code

FMT.Scanln finishes scanning when it hits a carriage return.

1.3.4 bufio.NewReader

Sometimes we want to get the input in its entirety, and the input may contain Spaces, in which case we can use the Bufio package. Example code is as follows:

func bufioDemo(a) {
	reader := bufio.NewReader(os.Stdin) // Generate read objects from standard input
	fmt.Print("Please enter:")
	text, _ := reader.ReadString('\n') // Read the newline
	text = strings.TrimSpace(text)
	fmt.Printf("%#v\n", text)
}
Copy the code

1.3.5 Fscan series

These functions are similar to fmt.Scan, fmt.Scanf, and fmt.Scanln, except that they read data from IO.Reader instead of standard input.

func Fscan(r io.Reader, a ...interface{}) (n int, err error)
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)
Copy the code

1.3.6 Sscan series

These functions are similar to fmt.Scan, fmt.Scanf, and fmt.Scanln, except that instead of reading from standard input, they read from a specified string.

func Sscan(str string, a ...interface{}) (n int, err error)
func Sscanln(str string, a ...interface{}) (n int, err error)
func Sscanf(str string, format string, a ...interface{}) (n int, err error)
Copy the code

2. Time package

The time package provides functions for displaying and measuring time. The calendar is calculated using the Gregorian calendar.

2.1 Time Type

Time. time indicates the time. We can use time.now () to get the current time object, and then get the time object’s year, month, day, hour, minute, second, etc. Example code is as follows:

func timeDemo(a) {
	now := time.Now() // Get the current time
	fmt.Printf("current time:%v\n", now)

	year := now.Year()     / / year
	month := now.Month()   / / month
	day := now.Day()       / /,
	hour := now.Hour()     / / hour
	minute := now.Minute() / / minute
	second := now.Second() / / SEC.
	fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
}
Copy the code

2.2 the timestamp

The timestamp is the total number of milliseconds since January 1, 1970 (08:00:00GMT) to the current time. It is also known as Unix timestamp.

Example code for obtaining a timestamp based on a time object is as follows:

func timestampDemo(a) {
	now := time.Now()            // Get the current time
	timestamp1 := now.Unix()     / / timestamp
	timestamp2 := now.UnixNano() // A nanosecond timestamp
	fmt.Printf("current timestamp1:%v\n", timestamp1)
	fmt.Printf("current timestamp2:%v\n", timestamp2)
}
Copy the code

You can convert a timestamp to a time format using the time.unix () function.

func timestampDemo2(timestamp int64) {
	timeObj := time.Unix(timestamp, 0) // Convert the timestamp to time format
	fmt.Println(timeObj)
	year := timeObj.Year()     / / year
	month := timeObj.Month()   / / month
	day := timeObj.Day()       / /,
	hour := timeObj.Hour()     / / hour
	minute := timeObj.Minute() / / minute
	second := timeObj.Second() / / SEC.
	fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
}
Copy the code

2.3 Time Interval

Time. Duration is a type defined by the time package that represents the elapsed time between two points in time in nanoseconds. Duration indicates an interval of time. The longest period of time available is about 290 years.

The constants of the interval type defined in the time package are as follows:

const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)
Copy the code

For example, time.Duration indicates 1 nanosecond, and time.Second indicates 1 Second.

2.4 Time Operation

Against 2.4.1 the Add

We may encounter the requirement of time + time interval in the daily coding process. The time object of Go language provides Add methods as follows:

func (t Time) Add(d Duration) Time
Copy the code

For example, find the time after an hour:

func main(a) {
	now := time.Now()
	later := now.Add(time.Hour) // The current time plus the time after 1 hour
	fmt.Println(later)
}
Copy the code

2.4.2 Sub

Find the difference between the two times:

func (t Time) Sub(u Time) Duration
Copy the code

Returns a time period t-u. If the result exceeds the maximum/minimum that Duration can represent, the maximum/minimum value is returned. To get the time point t-d (d is Duration), use t.dd (-d).

2.4.3 Equal

func (t Time) Equal(u Time) bool
Copy the code

To determine whether two time zones are the same, the time zone is considered. Therefore, the time of different time zone standards can be correctly compared. Unlike t==u, this method also compares location and time zone information.

2.4.4 Before

func (t Time) Before(u Time) bool
Copy the code

Return true if t represents a point in time before u; Otherwise return false.

2.4.5 After

func (t Time) After(u Time) bool
Copy the code

Return true if t represents a point in time after u; Otherwise return false.

2.5 timer

Use time.Tick to set a timer, which is essentially a channel.

func tickDemo(a) {
	ticker := time.Tick(time.Second) // Define a one-second interval timer
	for i := range ticker {
		fmt.Println(i)// Tasks that are executed every second}}Copy the code

2.6 Time Formatting

There is a built-in Format method for formatting time types. It should be noted that in Go language, the time template for formatting time is not the common Y-m-d H: m :S, but the birth time of Go is 15:04 on January 2, 2006 (2006 1 2 3 4). Maybe that’s the romance of the techie.

Add: Specify PM if you want to format to 12-hour mode.

func formatDemo(a) {
	now := time.Now()
	// The formatted template is Go born at 15:04 Mon Jan, 2 January 2006
	// 24-hour system
	fmt.Println(now.Format("The 2006-01-02 15:04:05. Mon 000 Jan"))
	// 12-hour system
	fmt.Println(now.Format(2006-01-02 03:04:05.000 PM Mon Jan"))
	fmt.Println(now.Format("2006/01/02 15:04"))
	fmt.Println(now.Format("15:04 2006/01/02"))
	fmt.Println(now.Format("2006/01/02"))}Copy the code

2.6.1 Time to parse string format

now := time.Now()
fmt.Println(now)
// Load the time zone
loc, err := time.LoadLocation("Asia/Shanghai")
iferr ! =nil {
	fmt.Println(err)
	return
}
// Parses the string time in the specified time zone and format
timeObj, err := time.ParseInLocation("2006/01/02 15:04:05"."2019/08/04 14:15:20", loc)
iferr ! =nil {
	fmt.Println(err)
	return
}
fmt.Println(timeObj)
fmt.Println(timeObj.Sub(now))
Copy the code

3. Structures in Go

3.1 Type aliases and custom types

3.1.1 User-defined Types

There are some basic data types in Go, such as string, integer, floating point, Boolean, etc. In Go, you can use the type keyword to define custom types.

A custom type defines an entirely new type. We can define it based on built-in primitive types, or we can define it through structs. Such as:

// define MyInt as an int
type MyInt int
Copy the code

By definition of the type keyword, MyInt is a new type that has the properties of int.

3.1.2 Type Aliases

Type aliases are a new feature added in the Go1.9 release.

Type aliasing states that TypeAlias is simply an alias of Type, and TypeAlias is essentially the same Type as Type. For example, when a child has a nickname, a baby name, after school with a scientific name, The English teacher will give him An English name, but these names refer to him.

type TypeAlias = Type
Copy the code

Rune and byte are type aliases we’ve seen before. They are defined as follows:

type byte = uint8
type rune = int32
Copy the code

3.1.3 Difference between a type definition and a type alias

The following code illustrates the apparent difference between a type alias and a type definition with just an equal sign.

// Type definition
type NewInt int

// Type alias
type MyInt = int

func main(a) {
	var a NewInt
	var b MyInt
	
	fmt.Printf("type of a:%T\n", a) //type of a:main.NewInt
	fmt.Printf("type of b:%T\n", b) //type of b:int
}
Copy the code

The result shows that the type of a is main.NewInt, which represents the NewInt type defined under the main package. B is of type int. The MyInt type only exists in the code, and does not exist when the compilation is complete.

3.2 structure

The language of the basic attributes of basic data types can say a few things, but when we want to say a thing of all or part of the property, this time with a single basic data type obviously couldn’t meet the demand, the language provides a custom data types, multiple basic data types can be encapsulated, the data type is called structure, Struct. So we can define our own type from structs.

Go language through struct to achieve object-oriented.

3.2.1 Definition of structure

Use the type and struct keywords to define a structure in the following format:

typeType namestruct{Field name Field Type Field name Field type... }Copy the code

Among them:

  • Type name: Identifies the name of a custom structure that cannot be repeated within the same package.
  • Field name: Indicates the structure field name. The field names in the structure must be unique.
  • Field type: Represents the specific type of a structure field.

For example, we define a Person structure as follows:

type person struct {
	name string
	city string
	age  int8
}
Copy the code

Fields of the same type can also be written on a single line,

type person1 struct {
	name, city string
	age        int8
}
Copy the code

This gives us a custom type of Person with three fields, name, city, and age, representing name, city, and age, respectively. This makes it easy to use the Person structure to represent and store human information in your program.

The base data types built into the language are used to describe a value, while constructs are used to describe a set of values. For example, a person has a name, age, city of residence, etc., which is essentially an aggregated data type

3.2.2 Structure instantiation

Memory is actually allocated only when the structure is instantiated. That is, the structure’s fields must be instantiated before they can be used.

Structs themselves are types, and we can declare structs using the var keyword just as we declare built-in types.

varStruct instance Struct typeCopy the code

3.2.3 Basic Instantiation

Here’s an example:

type person struct {
	name string
	city string
	age  int8
}

func main(a) {
	var p1 person
	p1.name = shahenaza
	p1.city = "Beijing"
	p1.age = 18
	fmt.Printf("p1=%v\n", p1)  //p1={1}
	fmt.Printf("p1=%#v\n", p1) //p1=main. Person {name:" ", city:" ", age:18}
}
Copy the code

We use. To access the structure’s fields (member variables), such as p1.name and p1.age.

3.2.4 Anonymous structure

Anonymous structures can also be used in situations such as defining some temporary data structures.

package main
     
import (
    "fmt"
)
     
func main(a) {
    var user struct{Name string; Age int}
    user.Name = "The Little Prince"
    user.Age = 18
    fmt.Printf("%#v\n", user)
}
Copy the code

3.2.5 Creating a Pointer Structure

We can also get the address of the structure by instantiating it using the new keyword. The format is as follows:

var p2 = new(person)
fmt.Printf("%T\n", p2)     //*main.person
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:"", city:"", age:0}
Copy the code

We can see from the printed result that P2 is a structure pointer.

Note that the Go language supports direct use of structure Pointers. To access the members of the structure.

var p2 = new(person)
p2.name = "The Little Prince"
p2.age = 28
p2.city = "Shanghai"
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:" prince ", city:" Shanghai ", age:28}
Copy the code

3.2.6 Instantiate the address of the structure

Fetching the address of a structure using & is equivalent to a new instantiation of the structure type.

p3 := &person{}
fmt.Printf("%T\n", p3)     //*main.person
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"", city:"", age:0}
p3.name = "Seven metres"
p3.age = 30
p3.city = "Chengdu"
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:" ", city:" ", age:30}
Copy the code

P3. name = “7 meters” (*p3). Name = “7 meters” (*p3).

3.2.7 Structure initialization

The member variables of an uninitialized structure are zero values corresponding to their type.

type person struct {
	name string
	city string
	age  int8
}

func main(a) {
	var p4 person
	fmt.Printf("p4=%#v\n", p4) //p4=main.person{name:"", city:"", age:0}
}
Copy the code

3.2.8 Initialization using Key/Value Pairs

When a structure is initialized using a key-value pair, the value pair should be the initial value of the field that the key corresponds to.

p5 := person{
	name: "The Little Prince",
	city: "Beijing",
	age:  18,
}
fmt.Printf("p5=%#v\n", p5) //p5=main. Person {name:" little prince ", city:" Beijing ", age:18}
Copy the code

Structure Pointers can also be initialized with key-value pairs, for example:

p6 := &person{
	name: "The Little Prince",
	city: "Beijing",
	age:  18,
}
fmt.Printf("p6=%#v\n", p6) //p6=&main.person{name:" little prince ", city:" Beijing ", age:18}
Copy the code

If a field has no initial value, the field may not be written. At this point, the value of a field that does not specify an initial value is zero for that field type.

p7 := &person{
	city: "Beijing",
}
fmt.Printf("p7=%#v\n", p7) P7 =&main.person{name:"", city:" Beijing ", age:0}
Copy the code

3.2.9 Initialize with a list of values

When initializing a structure, you can write the value directly instead of the key:

p8 := &person{
	shahenaza."Beijing".28,
}
fmt.Printf("p8=%#v\n", p8) //p8=&main.person{name:" ", city:" ", age:28}
Copy the code

When initializing with this format, note:

  1. All fields of a structure must be initialized.
  2. The initial values must be filled in the same order as the fields are declared in the structure.
  3. This method cannot be used with key value initialization.

3.3 Internal structure layout

The structure occupies a contiguous chunk of memory.

type test struct {
	a int8
	b int8
	c int8
	d int8
}
n := test{
	1.2.3.4,
}
fmt.Printf("n.a %p\n", &n.a)
fmt.Printf("n.b %p\n", &n.b)
fmt.Printf("n.c %p\n", &n.c)
fmt.Printf("n.d %p\n", &n.d)
Copy the code

Output:

n.a 0xc0000a0060
n.b 0xc0000a0061
n.c 0xc0000a0062
n.d 0xc0000a0063
Copy the code

Get proper memory alignment in Go

3.3.1 Empty structure

Empty structures do not take up space.

var v struct{}
fmt.Println(unsafe.Sizeof(v))  / / 0
Copy the code

3.4 Constructors

Go constructs do not have constructors; we can implement them ourselves. For example, the code below implements a Constructor for Person. Since struct is a value type, the value copy performance overhead is high if the structure is complex, so this constructor returns the structure pointer type.

func newPerson(name, city string, age int8) *person {
	return &person{
		name: name,
		city: city,
		age:  age,
	}
}
Copy the code

Calling the constructor

p9 := newPerson("Zhang"."Sha".90)
fmt.Printf("%#v\n", p9) //&main.person{name:" zhang3 ", city:" shahe ", age:90}
Copy the code

3.5 Methods and Receivers

A Method in Go is a function that acts on a particular type of variable. This particular type of variable is called Receiver. The concept of a receiver is similar to this or self in other languages.

Methods are defined in the following format:

func (Receiver variable Receiver type)The method name(Parameter list) (Return parameter){function body}Copy the code

Among them,

  • Receiver variables: When naming parameter variables in receivers, it is officially recommended to use the lowercase letters of the receiver type name insteadself,thisOr something like that. For example,PersonThe recipient variable of the type should be namedp.ConnectorThe recipient variable of the type should be namedcAnd so on.
  • Receiver type: The receiver type is similar to the parameter type and can be pointer or non-pointer.
  • Method name, argument list, return arguments: the format is the same as the function definition.

Here’s an example:

/ / Person structure
type Person struct {
	name string
	age  int8
}

//NewPerson constructor
func NewPerson(name string, age int8) *Person {
	return &Person{
		name: name,
		age:  age,
	}
}

// How to Dream
func (p Person) Dream(a) {
	fmt.Printf("%s dream is to learn Go! \n", p.name)
}

func main(a) {
	p1 := NewPerson("The Little Prince".25)
	p1.Dream()
}
Copy the code

The difference between methods and functions is that functions are not of any type and methods are of a specific type.

3.5.1 Receiver of pointer type

The receiver of a pointer type consists of a pointer to a structure. Due to the nature of Pointers, any member variable of the receiver pointer that is modified when a method is called is valid after the method ends. This approach is very similar to this or self in other object-oriented languages. For example, we add a SetAge method for Person to change the age of the instance variable.

// SetAge sets p's age
// Use pointer receiver
func (p *Person) SetAge(newAge int8) {
	p.age = newAge
}
Copy the code

To call this method:

func main(a) {
	p1 := NewPerson("The Little Prince".25)
	fmt.Println(p1.age) / / 25
	p1.SetAge(30)
	fmt.Println(p1.age) / / 30
}
Copy the code

3.5.2 Recipients of value types

When a method is applied to a value type receiver, the Go language makes a copy of the receiver’s value at runtime. The recipient’s member values can be obtained in the method of the value type receiver, but the modification operation is only for the copy and the recipient variable itself cannot be modified.

// SetAge2 sets p's age
// Use the value receiver
func (p Person) SetAge2(newAge int8) {
	p.age = newAge
}

func main(a) {
	p1 := NewPerson("The Little Prince".25)
	p1.Dream()
	fmt.Println(p1.age) / / 25
	p1.SetAge2(30) // (*p1).SetAge2(30)
	fmt.Println(p1.age) / / 25
}
Copy the code

3.5.3 When should pointer type receivers be used

  1. You need to modify the value in the receiver
  2. The receiver is a large object with a high copy cost
  3. To ensure consistency, if one method uses pointer receivers, other methods should use pointer receivers as well.

3.6 Adding methods of any Type

In the Go language, the receiver can be of any type, not just a structure, but any type can have methods. For example, we can use the type keyword to define new custom types based on the built-in int type, and then add methods to our custom types.

//MyInt defines int as a custom MyInt type
type MyInt int

SayHello adds a SayHello method to MyInt
func (m MyInt) SayHello(a) {
	fmt.Println("Hello, I'm an int.")}func main(a) {
	var m1 MyInt
	m1.SayHello() // I'm an int.
	m1 = 100
	fmt.Printf("%#v %T\n", m1, m1) //100 main.MyInt
}
Copy the code

Note: Non-native types cannot define methods, which means we cannot define methods for other package types.

3.7 Anonymous fields of a structure

A structure allows its member fields to be declared without a field name but only with a type. Such nameless fields are called anonymous fields.

//Person structure the Person type
type Person struct {
	string
	int
}

func main(a) {
	p1 := Person{
		"The Little Prince".18,
	}
	fmt.Printf("%#v\n", p1)        //main.Person{string:" Beijing ", int:18}
	fmt.Println(p1.string, p1.int) / / 18 in Beijing
}
Copy the code

The structure requires that the field name must be unique. Therefore, only one anonymous field of the same type can exist in a structure.

3.8 Nested structures

A structure can contain another structure or structure Pointers nested within it, as shown in the sample code below.

//Address Address structure
type Address struct {
	Province string
	City     string
}

//User User structure
type User struct {
	Name    string
	Gender  string
	Address Address
}

func main(a) {
	user1 := User{
		Name:   "The Little Prince",
		Gender: "Male",
		Address: Address{
			Province: "Shandong",
			City:     Weihai "",
		},
	}
	fmt.Printf("user1=%#v\n", user1)//user1=main.User{Name:" little ", Gender:" male ", Address:main.Address{Province:" shandong ", City:" Weihai "}}
}
Copy the code

3.8.1 Nested Anonymous Fields

The Address structure nested in the user structure above can also take the form of an anonymous field, for example:

//Address Address structure
type Address struct {
	Province string
	City     string
}

//User User structure
type User struct {
	Name    string
	Gender  string
	Address // Anonymous field
}

func main(a) {
	var user2 User
	user2.Name = "The Little Prince"
	user2.Gender = "Male"
	user2.Address.Province = "Shandong"    // Anonymous fields use the type name as the field name by default
	user2.City = Weihai ""                // Anonymous fields can be omitted
	fmt.Printf("user2=%#v\n", user2) //user2=main.User{Name:" little ", Gender:" male ", Address:main.Address{Province:" shandong ", City:" Weihai "}}
}
Copy the code

When accessing a structure member, the structure will first look for that field, and if it cannot find it, it will look for the nested anonymous field.

3.8.2 Field name conflicts in nested structures

The same field name may exist inside a nested structure. In this case, you can avoid ambiguity by specifying a specific inline structure field name.

//Address Address structure
type Address struct {
	Province   string
	City       string
	CreateTime string
}

// the Email structure
type Email struct {
	Account    string
	CreateTime string
}

//User User structure
type User struct {
	Name   string
	Gender string
	Address
	Email
}

func main(a) {
	var user3 User
	user3.Name = shahenaza
	user3.Gender = "Male"
	// user3.CreateTime = "2019" //ambiguous selector user3.CreateTime
	user3.Address.CreateTime = "2000" // Specify CreateTime in the Address structure
	user3.Email.CreateTime = "2000"   // Specify CreateTime in the Email structure
}
Copy the code

3.9 “Inheritance” of structure

The use of constructs in Go also enables object-oriented inheritance in other programming languages.

/ / Animal Animal
type Animal struct {
	name string
}

func (a *Animal) move(a) {
	fmt.Printf("% s will move! \n", a.name)
}

/ / the Dog Dog
type Dog struct {
	Feet    int8
	*Animal // Implement inheritance through nested anonymous structures
}

func (d *Dog) wang(a) {
	fmt.Printf("%s will bark ~\n", d.name)
}

func main(a) {
	d1 := &Dog{
		Feet: 4,
		Animal: &Animal{ // Note that the structure pointer is nested
			name: "Le le",
		},
	}
	d1.wang() // Lele can wang Wang wang ~
	d1.move() // Lele can move!
}
Copy the code

3.10 Visibility of structure fields

A field in a structure that starts with uppercase indicates publicly accessible, and lowercase indicates private (accessible only in the package that defines the current structure).

3.11 Structure and JSON serialization

JSON(JavaScript Object Notation) is a lightweight data interchange format. Easy to read and write. It is also easy for machine parsing and generation. JSON key-value pairs are a way of storing JS objects. The key/value pair combinations are preceded by the key name and enclosed with double quotation marks (“”), separated by a colon:, followed by the value; Multiple key values are separated in English.

/ / Student Student
type Student struct {
	ID     int
	Gender string
	Name   string
}

/ / Class Class
type Class struct {
	Title    string
	Students []*Student
}

func main(a) {
	c := &Class{
		Title:    "101",
		Students: make([]*Student, 0.200),}for i := 0; i < 10; i++ {
		stu := &Student{
			Name:   fmt.Sprintf("stu%02d", i),
			Gender: "Male",
			ID:     i,
		}
		c.Students = append(c.Students, stu)
	}
	//JSON serialization: structure --> string in JSON format
	data, err := json.Marshal(c)
	iferr ! =nil {
		fmt.Println("json marshal failed")
		return
	}
	fmt.Printf("json:%s\n", data)
	//JSON deserialization: string in JSON format --> structure
	str := ` {" Title ":" 101 ", "Students" : [{" ID ": 0," Gender ":" male ", "Name" : "stu00"}, {" ID ": 1," Gender ":" male ", "Name" : "stu01"}, {" ID ": 2," Gender ":" Male ", "Name" : "stu02"}, {" ID ": 3," Gender ":" male ", "Name" : "stu03"}, {" ID ": 4," Gender ":" male ", "Name" : "stu04"}, {" ID ": 5," Gender ":" male ", "Name" : "stu05"}, {" ID ": 6," Gender ":" male ", "Name" : "stu06"}, {" ID ": 7," Gender ":" male ", "Name" : "stu07"}, {" ID ": 8," Gender ":" male ", "Name" : "stu08}" , {" ID ": 9," Gender ":" male ", "Name" : "stu09}]} `
	c1 := &Class{}
	err = json.Unmarshal([]byte(str), c1)
	iferr ! =nil {
		fmt.Println("json unmarshal failed!")
		return
	}
	fmt.Printf("%#v\n", c1)
}
Copy the code

3.12 Structure Tag

The Tag is the meta information of the structure that can be read at runtime via reflection. The Tag is defined after the structure field and is enclosed by a pair of backquotes in the following format:

`key1:"value1" key2:"value2"`
Copy the code

A tag structure consists of one or more key-value pairs. Keys and values are separated by colons, and values are enclosed in double quotes. Multiple key-value pairs can be set for the same structure field, with Spaces separating the different key-value pairs.

Note: When writing a Tag for a structure, you must strictly follow the rules for key-value pairs. The parsing code for structure tags is very fault tolerant, and if the format is incorrectly written, it will not be reported at compile time or run time, and will not be evaluated correctly by reflection. For example, don’t add Spaces between key and value.

For example, we define a Tag for json serialization for each field in the Student structure:

/ / Student Student
type Student struct {
	ID     int    `json:"id"` // Implement the key for serializing the field by specifying a tag
	Gender string // Json serialization uses the field name as key by default
	name   string // Private cannot be accessed by JSON packages
}

func main(a) {
	s1 := Student{
		ID:     1,
		Gender: "Male",
		name:   shahenaza,
	}
	data, err := json.Marshal(s1)
	iferr ! =nil {
		fmt.Println("json marshal failed!")
		return
	}
	fmt.Printf("json str:%s\n", data) / / json STR: {" id ": 1," Gender ":" male "}
}
Copy the code

3.13 Structure and method supplement knowledge points

Because both slice and Map data types contain Pointers to the underlying data, we need to be careful when copying them. Let’s look at the following example:

type Person struct {
	name   string
	age    int8
	dreams []string
}

func (p *Person) SetDreams(dreams []string) {
	p.dreams = dreams
}

func main(a) {
	p1 := Person{name: "The Little Prince", age: 18}
	data := []string{"Eat"."Sleep"."Beat the beans."}
	p1.SetDreams(data)

	// Do you really want to fix p1.dreams?
	data[1] = "No sleep"
	fmt.Println(p1.dreams)  // ?
}
Copy the code

The correct way to do this is to assign a structure in a method using a copy of the slice passed in.

func (p *Person) SetDreams(dreams []string) {
	p.dreams = make([]string.len(dreams))
	copy(p.dreams, dreams)
}
Copy the code

The same problem exists with the return values slice and map, which must be taken care of during actual coding.