Go 语言入门指南:基础语法和常用特性解析(2) | 青训营

63 阅读5分钟

指针

指针也是一个变量,但它是一种特殊的变量,因为它存储的数据不仅仅是一个普通的值,如简单的整数或字符串,而是另一个变量的内存地址。

go语言中的函数传参都是值传递,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)和*(根据地址取值)。

package main

import "fmt"

func add2(n int) {
	n += 2
}

func add2pt(n *int) {
	*n += 2
}

func swap(a int, b int) {
	a, b = b, a
}

//函数参数为指针类型
func swapWithPt(a *int, b *int) {
	*a, *b = *b, *a
}

func main() {
	n := 5
	add2(n)
	fmt.Println(n) // 5
	add2pt(&n)
	fmt.Println(n) // 7

	a, b := 2, 3
	swap(a, b)
	fmt.Println(a, b)
	swapWithPt(&a, &b)
	fmt.Println(a, b)
}

结构体

Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。

package main

import "fmt"

type user struct {
	name     string
	password string
}

func main() {
	a := user{name: "wang", password: "1024"}
	b := user{"wang", "1024"}
	c := user{name: "wang"}
	c.password = "1024"
	var d user
	d.name = "wang"
	d.password = "1024"

	fmt.Println(a, b, c, d)               // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
	fmt.Println(checkPassword(a, "1024")) // true
	fmt.Println(a.name) // wang

	fmt.Println(checkPassword2(&a, "1024")) // true
	fmt.Println(a.name) // test
}

// 值传递
func checkPassword(u user, password string) bool {
	u.name = "test"
	return u.password == password
}

// 指针传递
func checkPassword2(u *user, password string) bool {
	u.name = "test"
	return u.password == password
}
自定义类型

除了Go语言基本的数据类型string、整型、浮点型、布尔等数据类型, 我们可以通过type关键词 自定义类型。

type goal int

通过type 定义的goal就是一种新的类型,它只是具有int的特性,但不是int类型

类型别名

类型别名是一个类型的别称,本质上还是同一个类型。

type goal=int

常见的rune,byte,any就是类型别名

// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8

// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32

// any is an alias for interface{} and is equivalent to interface{} in all ways.
type any = interface{}
区别

其实最主要的区别是 自定义类型是新类型,类型别名依然是旧类型,只不过有了一个别名 新的名称 。

结构体的定义

使用typestruct关键字来定义结构体:

    type 类型名 struct {
        字段名 字段类型
        字段名 字段类型
    }
结构体实例

只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。 结合前面所说 结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型 或者是 := 语法糖(匿名结构体)。

匿名结构体
//var
var TyJJ struct{Name string; Age int} ; WxJJ.Name = "tyjj" ; TyJJ.Age = 18

//推荐
TyGG := struct {
		Name string
		Age int
	}{
		"tygg",
		18,
	}

结构体方法

在 Go 中有一个概念,它和方法有着同样的名字,并且大体上意思相同:Go 方法是作用在接收者(receiver)上的一个函数,接收者是某种类型的变量。因此方法是一种特殊类型的函数。

package main

import "fmt"

type user struct {
	name     string
	password string
}

//func (u user) checkPassword(password string) bool {
//	return u.password == password
//}
//
//func (u user) resetPassword(password string) {
//	u.password = password
//}

func (u *user) checkPassword(password string) bool {
	return u.password == password
}

func (u *user) resetPassword(password string) {
	u.password = password
}

func main() {
	a := user{name: "wang", password: "1024"}
	a.resetPassword("2048")
	fmt.Println(a.checkPassword("2048")) // true
}

错误处理

errors 库函数

package main

import (
	"errors"
	"fmt"
)

type user struct {
	name     string
	password string
}

func findUser(users []user, name string) (v *user, err error) {
	for _, u := range users {
		if u.name == name {
			return &u, nil
		}
	}
	return nil, errors.New("not found")
}

func main() {
	u, err := findUser([]user{{"wang", "1024"}, {"yuan", "1212"}}, "wang")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(u.name) // wang

	if u, err := findUser([]user{{"wang", "1024"}, {"yuan", "1212"}}, "li"); err != nil {
		fmt.Println(err) // not found
		return
	} else {
		fmt.Println(u.name)
	}
}

字符串操作

string 库函数

package main

import (
	"fmt"
	"strings"
)

func main() {
	a := "hello"
	fmt.Println(strings.Contains(a, "ll"))                // true
	fmt.Println(strings.Count(a, "l"))                    // 2
	fmt.Println(strings.HasPrefix(a, "he"))               // true
	fmt.Println(strings.HasSuffix(a, "llo"))              // true
	fmt.Println(strings.Index(a, "ll"))                   // 2
	fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
	fmt.Println(strings.Repeat(a, 2))                     // hellohello
	fmt.Println(strings.Replace(a, "e", "E", -1))         // hEllo
	fmt.Println(strings.Split("a-b-c", "-"))              // [a b c]
	fmt.Println(strings.ToLower(a))                       // hello
	fmt.Println(strings.ToUpper(a))                       // HELLO
	fmt.Println(len(a))                                   // 5
}

时间处理

time 库函数

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
	t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
	t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
	fmt.Println(t)                                                  // 2022-03-27 01:25:36 +0000 UTC
	fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
	fmt.Println(t.Format("2006-01-02 15:04:05"))                    // 2022-03-27 01:25:36
	diff := t2.Sub(t)
	fmt.Println(diff)                           // 1h5m0s
	fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
	t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
	if err != nil {
		panic(err)
	}
	fmt.Println(t3 == t)    // true
	fmt.Println(now.Unix()) // 1648738080
}

数字解析

strconv 库函数

package main

import (
	"fmt"
	"strconv"
)

func main() {
	f, _ := strconv.ParseFloat("1.234", 64)
	fmt.Println(f) // 1.234

	n, _ := strconv.ParseInt("111", 10, 64)
	fmt.Println(n) // 111

	n, _ = strconv.ParseInt("0x1000", 0, 64)
	fmt.Println(n) // 4096

	n2, _ := strconv.Atoi("123")
	fmt.Println(n2) // 123

	n2, err := strconv.Atoi("AAA")
	fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}