1. go Language Overview
go core programming direction:
- Blockchain R & D Engineer
- go server / Game Software Engineer
- go distributed / Cloud Computing Software Engineer
Advantages of go:
- data processing
- High concurrency
Why did google create go language:
- The hardware technology is updated frequently and the performance is improved rapidly. The existing language can not make rational use of the advantages of multi-core and multi CPU
- The computing power of the existing language is not enough, and the processing of large concurrency is not good enough
- Want to take into account the running speed and development speed
Brief history of development:
- In 2015, go1 5 release, removing the last remaining c code
- In 2017, go1.0 was released successively 8 and 1.9
- In 2018, go1.0 was released Version 10
go features:
- go=c+python
- It inherits many ideas from c language, such as pointer
- Automatic garbage collection
- Natural concurrency
- Support concurrency from the language level
- goroutine, a lightweight thread, can realize large concurrent processing and make efficient use of multi-core
- Implementation of concurrency model based on CPS
- Communication between different goroute s is realized through pipes
- Function can return multiple values
- New syntax: delay execution defer, slice slice, etc
2. Basic grammar
1. Variable usage
- Specify the variable type. If no value is assigned after declaration, the default value will be used
- Automatically derive types from values
- Even var is omitted, but use the: = character, which is equivalent to declaration + assignment
var i int fmt.Println("i=",i) var j = "hello" fmt.Println("j=",j) k := 10.5 fmt.Println("k=",k)
Note: the main function can run only after it is placed under the main package, as shown in the following figure.
2. Declare multiple variables at once
var i,j,k int fmt.Println("i=",i,"j=",j,"k=",k) var o,p,q = 10,"hello",10.5 fmt.Println("o=",o,"p=",p,"q=",q) r,s,t := 10,"hello",10.5 fmt.Println("r=",r,"s=",s,"t=",t)
3. Declare global variables
package main var n1 = 100 var n2 = "okk" var ( n3 = 36.9 n4 = "yes" ) func main() { }
4. Constant
const a int = 10
Constants must be initialized
Constants can only modify bool, numeric type (int, float series) and string type
5. go data type
Basic data type
- Numerical type
- Integer type (int,int8,int16,int32,int64,uint,uint8,uint16,uint32,uint64)
- Floating point type (float32,float64)
- Character type (there is no special character type, and byte is used to save single alphabetic characters)
- Boolean (bool)
- character string
Derived / complex data types
- Pointer
- array
- structural morphology
- The Conduit
- function
- Slice (dynamic array)
- Interface
- map
6. Value type and reference type
Value type: basic data type, array, structure
Reference types: pointer, slice, map, pipe, interface
7. Operator
The self increment and self decrement of golang can only be used as independent statements, not b:=a++
golang does not have + + i
3. go characters and strings
1. Differences between go characters
For other languages, strings consist of a string of characters, while go strings consist of a string of bytes.
var b1 byte = 'a' fmt.Println("b1=",b1) // Output 97 var b2 byte = 97 fmt.Printf("b2=%c\n",b2) // Output a b3 := 'you' fmt.Println("b2=",b3) // Output unicode code value
The following test character and Boolean types occupy a few bytes respectively.
b := 'a' success := false fmt.Println(unsafe.Sizeof(b)) // Output 4 fmt.Println(unsafe.Sizeof(success)) // Output 1
If the number of bytes encoded in UTF-8 of a character is greater than 1, byte cannot be saved, but int is no problem. As shown in the figure below.
2. Basic use of strings
var s1 = "hello"+"world" // Splicing s1+="hi" // Because go can not end with a semicolon, when the string splicing statement is too long and needs to wrap, the end of each line must end with a + sign s2 := "I am"+"One"+ "Chinese"+"hello"+ "world" s3 := `Output the string as is, which is suitable for outputting source code, etc.\n\t` fmt.Println(s1) fmt.Println(s2) fmt.Println(s3)
3. Display type conversion between basic data types
var a int = 9999 var b byte = byte(a) fmt.Println(b)
4. Conversion between String and basic type
The first method is to convert the basic type to string, as shown in the following code.
var a int = 100 s := fmt.Sprintf("%d", a) // Use the Sprintf function for conversion fmt.Printf("type=%T,value=%q",s,s) // Output the type and value of% s,%q one more double quotation mark than the output result of% s
The basic type is converted to string. The second method is shown in the following code.
var a int = 100 s := strconv.FormatInt(int64(a), 2) fmt.Printf("type=%T,value=%q",s,s) // f indicates format, 10 indicates decimal places, 10 digits are reserved, and 64 indicates that the decimal place is float64 s = strconv.FormatFloat(12.99, 'f', 10, 64) fmt.Printf("type=%T,value=%q",s,s)
string to the basic type, as shown in the following code.
b, err := strconv.ParseBool("fals1") // b, _ := strconv.ParseBool("true") / / if you don't want to get err information, use_ fmt.Printf("%v",b) // If it cannot be converted to a valid value, it will be converted to the default value, and so will string to other types fmt.Println(err)
4. Get user input
// Mode 1 var name string var age int // fmt.Scanln(&name) // fmt.Println("your name is:", name) // Mode 2 fmt.Scanf("%s %d",&name,&age) fmt.Println("Your name is:",name,",Your age is:",age)
5. Generate random number
// Set seed rand.Seed(time.Now().Unix()) n:=rand.Intn(100)+1 fmt.Println(n)
6. Pointer
// Output address of basic type i := 10 fmt.Println(&i) // Declare a pointer of type * int, and the value of p itself is & I var p *int = &i fmt.Println(p) // Output the value of p itself fmt.Println(&p) // Address of output p fmt.Println(*p) // Output the value pointed to by p
7. Process control statement
1. if and switch
if 5>3 { fmt.Println("Hello") } // Supports defining variables in if if age:=10;age>9 { fmt.Println("hello") } score:=30 switch score { case 10,20: fmt.Println("Bad") // Auto break case 30,40: fmt.Println("it 's not bad"); fallthrough // Only one layer is penetrated by default default: fmt.Println("Go 3") } // This kind of writing is similar to if else switch { case score<10 || score>90:fmt.Println("weirdo") default:fmt.Println("Regular") } var service interface{} var y = 10 service = y switch service.(type) { case nil:fmt.Println("Empty type") case int:fmt.Println("int type") case float64:fmt.Println("float64 type") }
2. for loop
for i := 1; i < 10; i++ { fmt.Println("hello") } // It is equivalent to a while loop. There is no while keyword in go j:=1 for j<10{ fmt.Println("hi") j++ } // Two ways of writing infinite loop // for ;; {} or for {} // For range, traversable strings and arrays // The traditional way to traverse the string is to traverse by bytes, which cannot contain Chinese s:="hello,world in" for i:=0;i<len(s);i++{ fmt.Printf("%c\n",s[i]) } // For range is traversed by characters for index,item:=range s{ fmt.Printf("%d-%c\n",index,item) } // Turning a string into a slice can also traverse by character s2 := []rune(s) for i:=0;i<len(s2);i++{ fmt.Printf("%c\n",s2[i]) }
3. goto statement
label: fmt.Println("goto test1") fmt.Println("goto test2") goto label
8. Functions
1. Function core
Syntax:
func Function name (parameter list ) (Return value type list){ }
Note:
-
Placeholders can be used when receiving multiple return values_ Ignore a return value.
-
If there is only one return value, the return value type list may not be written.
-
The go function does not support overloading.
-
The parameter transfer of go function is value transfer. If you want to modify the variable value in the function, you can pass in the variable address and operate the variable with a pointer in the function.
Functions are also data types that can be assigned to variables, and functions can be used as formal parameters. The following code is shown.
// Define anonymous functions and assign values to variables mysum := func(a int,b int) int { return a+b } fmt.Printf("call mysum[%T][%d]",mysum,mysum(10,20))
User defined data types: type myint int, type mysum func(int,int) int, which is equivalent to alias. The following code is shown. This grammar is of little use
type lensum func(s1 string,s2 string)int var totallen lensum totallen = func(s1 string,s2 string) int { return len(s1)+len(s2) } fmt.Println("Custom type:",totallen("hello","hi"))
It also supports naming function return values, as shown in the following code. This grammar is of little use
func sum(a int,b int)(sum int,sub int){ sum = a+b sub = a-b return }
Variable parameters:
// args is a slice that can be accessed by index func sum2(args... int) int { var sum int for i := 0; i < len(args); i++ { sum +=args[i] } return sum }
Initialization function:
// Each source file can define an init function, which is executed before the main function and called by the go run framework func init(){ fmt.Println("Test_07_function.go Initialized") }
Function closure:
initClickCnt := func(initCnt int) func(int){ totalCnt := initCnt // totalCnt and cnt constitute the closure of the function. totalCnt is initialized only once, which is equivalent to a global variable, while cnt is equivalent to a local variable return func(cnt int) { totalCnt += cnt fmt.Println("Current hits:",totalCnt) } } printClickCnt := initClickCnt(100) printClickCnt(8) // 108 printClickCnt(10) // 118 printClickCnt(2) // 120
defer deferred execution:
deferTest := func() { // Relevant statements enter the defer stack. After the method is completed, the statements in the defer stack are executed in a later in first out manner. It can be used to close file handles, database connections, locks and other resources. defer fmt.Println("Close a resource") defer fmt.Println("Close a handle") fmt.Println("Execution logic") } deferTest()
2. System function
Time and date correlation functions:
now := time.Now() // Get current time fmt.Printf("%02d-%02d-%02d %02d:%02d:%02d\n",now.Year(),now.Month(),now.Day(),now.Hour(), now.Minute(),now.Second()) fmt.Println(now.Format("2006-01-02 15:04:05")) // It must be written like this time.Sleep(3*time.Second) // Sleep for 3 seconds
3. Built in function
len() finds the length of string and array
new() is used to allocate memory. It is mainly used to allocate value types (fill in default values) and return pointers. The following code is shown.
p := new(int) fmt.Printf("type[%T]Pointer value[%v]Pointer address[%v]The value pointed to by the pointer[%v]The type of value the pointer points to[%T]",p,p,&p,*p,*p)
make() is used to allocate memory, mainly to allocate reference types, and returns pointers
9. go language specification
1. Package specification
If you want to compile into an executable file, you need the main package. If you just write a library, you don't need the main package.
Execute the following command in gopath directory and compile it into an executable file:
// When compiling, you need to compile the folder where the main package is located // The executable file generated after compilation can be in the gopath directory. You can also specify the path and file name through the - o parameter go build -o bin/my.exe project_name/package_name/main
When import ing a package, the path is written from GOPATH/src without src.
There are multiple main functions under the main package. How to ignore them during compilation?
- Just add / / + build ignore at the top of the file where the main function to be ignored is located and leave at least one blank line.
2. Identifier specification
Try to match the package name with the directory name
If the variable name, function name and constant name are capitalized, they are public; otherwise, they are private
10. go language exception handling
func main() { // Test exception handling test() // Custom error customError := func(s string) error{ if(s == "Xiao Ming"){ return nil }else{ return errors.New("Parameter value is not Xiao Ming!") } } if err := customError("Xiao Zhang");err!=nil { panic(err) } } func test() { defer func() { if err:=recover();err != nil{ fmt.Println("test An exception occurred in the method") } }() // Write () to execute it a:=10 b:=0 c:=a/b fmt.Println(c) }
11. Arrays and slices
1. Array
// Several ways to define arrays // Mode 1 var arr [5]int arr[0] = 2 fmt.Println(arr[0]) // Mode 2 var arr2 = [5]int{1,2,3,4,5} fmt.Println(arr2[0]) // Mode 3 var arr3 = [...]int{1,2,3} fmt.Println(arr3[0]) //Mode 4, if you write Array type, otherwise slice var arr4 = [...]string{1:"Guan Yu",0:"Liu Bei",2:"Zheng Fei"} fmt.Printf("%T",arr4)
2. Slice
// Define slice // Method 1: reference array. If startIndex is 0 or endIndex is the array length, it can be omitted, such as arr [:] var slice []int = arr2[1:4] fmt.Println("Value of slice:",slice) fmt.Println("Number of elements sliced:",len(slice)) fmt.Println("Slice capacity:",cap(slice)) // Mode 2 var slice2 []int = make([]int,4,16) fmt.Println("Value of slice:",slice2) // Method 3: direct reference array var slice3 []int = []int{1,2,3,4,5} fmt.Println("Value of slice:",slice3) // Slice dynamic growth slice3 = append(slice3,6) fmt.Println("Value of slice:",slice3) // Slice copy (array not available) var slice4 []int = make([]int,10,10) copy(slice4,slice3) fmt.Println(slice4)
3. string and slice
The bottom layer of string is byte array, so it can also be sliced
// String can be converted into slice or [] byte s := "hello China" slice5 := []rune(s) for _,item:=range slice5 { fmt.Printf("%c",item) }
4. Multidimensional array
var arrtwo [3][4]int = [3][4]int{{1,2,3,4},{5,6,7,8},{9,10,11,12}} fmt.Println("\n",arrtwo)
12,Map
key type:
- Yes: bool, number, string, pointer, channel, interface, structure, array, etc
- No: slice, map, function, because these cannot be judged with = =
// map can be dynamically expanded var wordcnt map[string]int = make(map[string]int,10) wordcnt["Guan Yu"] = 20 // Initialize when declared var wordcnt2 map[string]int = map[string]int{ "Fei Zhang":20, "Zhao Yun":16, "Cao Cao":32, } fmt.Println(wordcnt2) //Delete a key. If you want to delete all keys, you can use the make function to allocate new memory delete(wordcnt2,"Fei Zhang") // lookup value,b := wordcnt2["Cao Cao"] fmt.Println(value,b) // Traversal, only for range can be used for k,v:=range wordcnt2 { fmt.Println(k,"=",v) } // map slice var mapslice []map[string]int = make([]map[string]int,2) // Dynamic increase element := map[string]int{ "hello":5, "ok":8, } mapslice = append(mapslice,element) fmt.Println(mapslice)
13. go language object oriented programming
1. Structure struct
Note:
- struct is similar to class.
- go object-oriented programming is very concise, without inheritance, method overloading, constructor, destructor, hidden this pointer and so on.
- go still has encapsulation, inheritance and polymorphism, but the implementation methods are different. For example, inheritance does not have the extends keyword, and inheritance is implemented through anonymous fields (combinations).
- Interface oriented programming is a very important feature of go.
- The address of the structure attribute is allocated consecutively
- When two different structures are converted, the corresponding fields need to be the same
- You can give each field a tag, which will be used in serialization
- Because the go method acts on the specified data type, it can also have methods not only struct, int, float, etc
- Type can implement string method (equivalent to toString method in Java)
type User struct { name string `json:"name"` age int `json:"age"` password string `json:"password"` } func (u *User) addAge(b int) { // The structure is a value type and is a value copy when parameters are passed. Therefore, the properties of the original struct cannot be modified // If you want to modify the properties of the original struct, you need to pass in the pointer, * User, and the underlying layer is optimized. You can replace (* U) with u.age age u.age = u.age+b } func main() { // Method 1: declare structure variables and assign values var u1 User = User{"Zhang San",10,"123456"} fmt.Println(u1) // Mode 2: var u2 *User = new(User) (*u2).name = "Li Si" u2.password = "ok" // It can also be written because: conversion is made at the bottom fmt.Println(*u2) // Mode 3 var u3 *User = &User{} u3.name="Wang Wu" // Call method u1.addAge(5) fmt.Println(u1.age) }
2. Inherit
Inheritance is implemented through anonymous fields.
type Animal struct { name string age int } type Dog struct { Animal owner string } func main() { dog := Dog{} dog.owner = "Zhang San" dog.name = "Labrador" dog.age = 1 fmt.Println(dog) }
Note:
- You can inherit all fields and methods, including private
- When the parent and child contain fields or methods with the same name, the proximity principle is adopted
- When multiple inheritance occurs, and there are fields or methods with the same name between multiple parent structures, you must specify which parent structure it is
3. Interface and polymorphism
type UserService interface { get() string insert() int } type UserServiceImpl struct { } func (service UserServiceImpl) get() string { fmt.Println("implement get method") return "name:Zhang San;age:10" } func (service UserServiceImpl) insert() int { fmt.Println("implement insert method") return 8 } func doService(service UserService) { fmt.Println(service.get()) fmt.Println(service.insert()) } func main() { doService(UserServiceImpl{}) }
Note:
- go does not have the implements keyword
- Only one user-defined type is required to implement the interface, and then all methods in the interface can be implemented
- The empty interface interface {} does not have any method, because it is considered that all types implement the interface, which is equivalent to the total Object class of Java
- Variables cannot be defined in an interface
- Interfaces can inherit
- The polymorphism in go is implemented through the interface and supports polymorphic parameters and polymorphic arrays
4. The difference between type assertion and forced conversion
// The difference between type assertion and forced conversion var b UserService var a interface{} = UserServiceImpl{} // Strong turn. An error is reported. Because the specific type of a is unknown, it cannot be forcibly converted // b = UserService(a) // // Type Asserts b = a.(UserService) doService(b) // Type assertion with detection c,ok:=a.(UserService) if ok { doService(c) }
14. File operation
1. Basic use
// Open file file, _ := os.OpenFile("F:/tmp/test.txt",os.O_RDONLY,os.ModePerm) // Close file defer file.Close() // Loop read file reader := bufio.NewReader(file) for{ line, err2 := reader.ReadString('\n') if err2 == io.EOF { // Indicates that the end of the file has been read break } fmt.Println(line) } // One time read file content, _ := ioutil.ReadFile("F:/tmp/test.txt") fmt.Println(content) // Write file writer := bufio.NewWriter(file) writer.WriteString("hello") writer.Flush() // Determine whether the file exists _, err := os.Stat("F:/tmp/test.txt") if err == nil { fmt.Println("existence") }else if os.IsNotExist(err){ fmt.Println("non-existent") }else{ fmt.Println("uncertain") } // File copy io.Copy(writer,reader)
2. Case
1. Split file
Description: divides a large file into n small files
Parameters:
- inFilePath large file path
- outFilePath small file storage directory
- splitLineNum line number array, such as [2,4,6], will be cut on lines 2, 4 and 6 of the large file respectively, and finally four small files will be generated
func Split(inFilePath string,outFilePath string,splitLineNum []int) { file, err := os.OpenFile(inFilePath, os.O_RDONLY, os.ModePerm) suffix := path.Ext(inFilePath) defer file.Close() if nil != err{ fmt.Println("File opening failed!") return } reader := bufio.NewReader(file) // initialize variable cnt := 0 index := 0 num := splitLineNum[index] splitFile,_ := os.OpenFile(outFilePath+"/split_"+fmt.Sprintf("%d",index)+suffix, os.O_APPEND|os.O_CREATE, os.ModePerm) writer := bufio.NewWriter(splitFile) defer splitFile.Close() for { line, err := reader.ReadString('\n') if io.EOF == err { break } // Judgment is enough to read the dividing line if cnt == num { // Be sure to flush before closing the file writer.Flush() splitFile.Close() // Change to the next file index++ if index < len(splitLineNum) { num = splitLineNum[index] } splitFile,_ = os.OpenFile(outFilePath+"/split_"+fmt.Sprintf("%d",index)+suffix, os.O_APPEND|os.O_CREATE, os.ModePerm) writer = bufio.NewWriter(splitFile) } writer.WriteString(line) cnt++ } writer.Flush() }
2. Calculate sub file size
Description: enter a path and output the size of all sub files under the path. By default, the file size is sorted from large to small
Parameters:
- inFilePath input path
- unit
func calculateChildFileSize(inFilePath string) int64{ stat, _ := os.Stat(inFilePath) file, _ := os.OpenFile(inFilePath, os.O_RDONLY, os.ModePerm) defer file.Close() if stat.IsDir() { childs, _ := file.Readdir(-1) var total int64 for _,item := range childs{ total += calculateChildFileSize(inFilePath + "/" + item.Name()) } return total }else{ return stat.Size() } } func ChildFileSize(inFilePath string,unit string){ file, _ := os.OpenFile(inFilePath, os.O_RDONLY, os.ModePerm) defer file.Close() childs, _ := file.Readdir(-1) var fileSizeMap map[int64]string = make(map[int64]string,10) for _,item := range childs{ fileSizeMap[calculateChildFileSize(inFilePath+"/"+item.Name())] = item.Name() } var keys []int for k,_ := range fileSizeMap { keys = append(keys,int(k)) } sort.Ints(keys) for i:=len(keys)-1;i>=0;i--{ if unit == "KB" { fmt.Println(fileSizeMap[int64(keys[i])],"\t",keys[i]/1024,"KB") }else if unit == "MB" { fmt.Println(fileSizeMap[int64(keys[i])],"\t",keys[i]/(1024*1024),"MB") }else{ fmt.Println(fileSizeMap[int64(keys[i])],"\t",keys[i],"B") } } }
3. File synchronization
Description: synchronize files from one place to another. The default synchronization mode is overwrite. However, files with destination but no source will not be deleted
Parameters:
- dst: destination path
- src: source file or source folder
func Sync(dst string,src string) { // Determine whether it is a folder, assuming that src exists stat, _ := os.Stat(src) if !stat.IsDir() { f1, _ := os.OpenFile(src, os.O_RDONLY, os.ModePerm) if _, err := os.Stat(dst+"/"+path.Base(src));nil == err || os.IsExist(err){ // If it exists, delete the previous file os.Remove(dst+"/"+path.Base(src)) } f2, _ := os.OpenFile(dst+"/"+path.Base(src), os.O_RDWR|os.O_CREATE, os.ModePerm) defer f1.Close() defer f2.Close() io.Copy(f2,f1) }else { if _, err := os.Stat(dst+"/"+path.Base(src));nil != err && os.IsNotExist(err){ // If it does not exist, create a folder os.Mkdir(dst+"/"+path.Base(src),os.ModePerm) } f, _ := os.OpenFile(src, os.O_RDONLY, os.ModePerm) childs, _ := f.Readdir(-1) for _,item := range childs{ Sync(dst+"/"+path.Base(src),src+"/"+item.Name()) } } }
15. Command line parameters
You can use OS Args gets all command line parameters.
More conveniently, you can specify a parameter name (such as - name). When you specify a parameter name, you can obtain the parameter in the following way.
var name string flag.Stringvar(&name,"name","Default value","user name") flag.Parse()
16. Serialization and deserialization
type Student struct { Name string `json:"name"` Age int `json:"age"` Score int `json:"score"` } // serialize stu := Student{"Zhang San",23,98} jsonStr, _ := json.Marshal(stu) fmt.Println(string(jsonStr)) // Deserialization var stu2 Student _ = json.Unmarshal([]byte(jsonStr), &stu2) fmt.Println(stu2)
17. goroutine and channel
1. goroutine overview
go can easily build tens of thousands of collaborative processes because it is optimized at the bottom, which can be understood as a more lightweight thread
go collaboration features:
- Independent stack space
- Shared program heap space
- Scheduling is controlled by users
If the main thread exits, the coroutine will exit even if it has not finished executing.
The main thread is a physical thread that directly acts on the CPU. It is a heavyweight and consumes CPU resources.
The collaboration process is started from the main thread. It is a lightweight thread. It is in a logical state and consumes relatively little resources.
Other programming languages are based on threads. Opening too many threads consumes a lot of resources, which makes go have great concurrency advantages.
2. goroutine concurrency model
MPG mode:
- M: The main thread of the operating system (which is a physical thread)
- P: Context required for collaborative process execution
- G: Synergetic process
A program can have multiple Ms. when multiple MS run on different CPU s, they are parallel.
Each M corresponds to a P, a running G and a co process waiting queue.
How to start a collaborative process?
go test()
3. Concurrent security
When there is a concurrent security problem, compile with the - race parameter, and then execute the exe file. The result is correct.
How to ensure thread safety:
-
lock
var lock sync.Mutex lock.Lock() lock.Unlock()
-
channel (communication between different goroutine s)
4. channel overview
A channel is essentially a queue.
When multiple goroutine s access the channel, there is no need to lock it. The channel itself is thread safe.
The channel has types, and the string channel can only store string types.
Basic use of channel:
// Declare channel var intChan chan int intChan = make(chan int,10) // Write data. If you write too much, you will report an error intChan<-10 intChan<-20 intChan<-30 intChan<-40 // This capacity will not grow dynamically fmt.Println(len(intChan),cap(intChan)) // Read the data and report an error if you read too much ele := <-intChan fmt.Println(ele) // Close the pipeline. After closing, you can only read but not write close(intChan) // The channel can be traversed, but if the channel is not closed, an error will be reported. Otherwise, the channel can be traversed normally for item:=range intChan{ fmt.Println(item) }
matters needing attention:
- channel can be declared read-only or write only.
- Using select can solve the blocking problem of reading data from the pipeline.
- Using recover in goroutine can avoid goroutine exiting because of panic.
18. Reflection
The type of the variable (reflect.Type interface) can be obtained through reflection (reflect.TypeOf function).
The value of the variable (reflect.Value structure) can be obtained through reflection (reflect.ValueOf function).
19. Network programming
func server() { server, err := net.Listen("tcp", "0.0.0.0:8888") if err != nil { fmt.Println(err) return } defer server.Close() fmt.Println("The server is started successfully!") for { client, _ := server.Accept() fmt.Println("Client connection succeeded!") var data []byte = make([]byte,128) client.Read(data) fmt.Println("The server received the message:",string(data)) } } func client() { client, _ := net.Dial("tcp", "localhost:8888") defer client.Close() data := []byte("Hello, golang!") client.Write(data) } func main() { go server() time.Sleep(1*time.Second) client() }