[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:
- All fields of a structure must be initialized.
- The initial values must be filled in the same order as the fields are declared in the structure.
- 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 instead
self
,this
Or something like that. For example,Person
The recipient variable of the type should be namedp
.Connector
The recipient variable of the type should be namedc
And 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
- You need to modify the value in the receiver
- The receiver is a large object with a high copy cost
- 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.