go语言基础23实例

go语言基础

文章目录

  • go语言基础
    • 实例1-你好,世界
    • 实例2-变量
    • 实例3-循环
    • 实例4-条件
    • 实例5-条件分支
    • 实例6-数组
    • 实例7-切片
    • 实例8-map映射
    • 实例9-range语法
    • 实例10-函数
    • 实例11-指针
    • 实例12-结构体
    • 实例13-结构体方法
    • 实例14-错误处理
    • 实例15-字符串
    • 实例16-字符串格式化
    • 实例17-json
    • 实例18-时间
    • 实例19-strconv字符串转数字
    • 实例20-环境变量的获取和设置与外部命令的执行
    • 实例21-并发
    • 实例22-通道
    • 实例23-接口

实例1-你好,世界

package main // 这里需要是主包
// 导入时用小括号扩起
import (
	"fmt"
)
// 当然对于单个包时可以直接写明的
// import "fmt"

// 主函数即是入口,下面的格式化输出并且会发生换行
func main() {
	fmt.Println("hello world")
	// fmt.Println("hello world");go语言最后是不用写分号的,但是写了也可以正常运行,
	// 因为编译器是会自动帮我们做这些事情的
}

实例2-变量

package main
// 导入多个包需要分分行,用小括号扩起
import (
	"fmt"
	"math"
)
// 如果需要放置在同一行则需要加分号
// import (
// 	"fmt";	"math"
// )
func main() {
// 变量用 var 标识 和 js 倒是相像 会根据初值决定变量类型
	var a = "initial"
	var b, c int = 1, 2
	var d = true
	// 显示的说明是64位浮点数 类型说明是在后面放置 和以前学的c和java等语言不同 e的初始值应该为0
	var e float64
	// 将变量e转换为float32类型,并将结果赋值给变量f。由于e的值为0,因此f的值也为0。
	f := float32(e)
	// 将字符串"foo"拼接到字符串a的后面,并将结果赋值给变量g。因此g的值为"initialfoo"。
	g := a + "foo"
	fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
	fmt.Println(g)                // initialapple
// 常量定义
	const s string = "constant"
	const h = 500000000
	// 科学计数法 3*10^20
	const i = 3e20 / h
	// math.Sin 计算正弦值
	fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}

实例3-循环

package main

import "fmt"

func main() {
// 在Go语言中,:= 是一个简短声明变量的语法。它可以替代传统的 var 关键字和类型声明,让代码更加简洁易读。例如:     
// x := 10 // 等价于 var x int = 10
// y := "hello" // 等价于 var y string = "hello"   
// 需要注意的是,使用 := 声明变量时,必须为变量赋初值,否则会导致编译错误。

	i := 1
	// for循环 break用于跳出循环
	for {
		fmt.Println("loop")
		break
	}
	// 带条件的for循环
	for j := 7; j < 9; j++ {
		fmt.Println(j)
	}

	for n := 0; n < 5; n++ {
		if n%2 == 0 {
			// continue语句用于回到条件判断处 跳过后面的语句
			continue
		}
		fmt.Println(n)
	}
	// 条件的另一种写法
	for i <= 3 {
		fmt.Println(i)
		i = i + 1
	}
}

实例4-条件

package main

import "fmt"

func main() {
// if条件判断语句
	if 7%2 == 0 {
		fmt.Println("7 is even")
	} else {
		fmt.Println("7 is odd")
	}

	if 8%4 == 0 {
		fmt.Println("8 is divisible by 4")
	}
// 这段代码定义了一个名为num的变量,并使用if语句对其进行判断。
// 在if语句中可以使用简短声明变量的方式来为变量赋初值,这种方式也被称为“短声明”。
	if num := 9; num < 0 {
		fmt.Println(num, "is negative")
	} else if num < 10 {
		fmt.Println(num, "has 1 digit")
	} else {
		fmt.Println(num, "has multiple digits")
	}
}

实例5-条件分支

package main

import (
	"fmt"
	"time"
)

func main() {
// 条件分支语句 不需要像c一样每个有break
	a := 2
	switch a {
	case 1:
		fmt.Println("one")
	case 2:
		fmt.Println("two")
	case 3:
		fmt.Println("three")
	case 4, 5:
		fmt.Println("four or five")
	default:
		fmt.Println("other")
	}
// t := time.Now():声明一个名为t的变量,并将其初始化为当前时间。
	t := time.Now()
	fmt.Println(t)
	switch {
		// 获取小时数
	case t.Hour() < 12:
		fmt.Println("It's before noon")
	default:
		fmt.Println("It's after noon")
	}
}

实例6-数组

package main

import "fmt"

func main() {
// 整形 数组 大小为5
	var a [5]int
	a[4] = 100
	// 初值为0
	fmt.Println("get:", a[2])
	// len(数组名) 获取数组长度
	fmt.Println("len:", len(a))
	// 中间可以加空格也可以不加 确实不加更好看
	b := [5]int{1, 2, 3, 4, 5}
	fmt.Println(b) 

	var twoD [2][3]int
	for i := 0; i < 2; i++ {
		for j := 0; j < 3; j++ {
			twoD[i][j] = i + j
		}
	}

	fmt.Println("2d: ", twoD)
	// 对二维数组进行len计算长度计算的是行长度 2
	fmt.Println(len(twoD))
	// 二维数组的行计算长度进行len计算得到的是列长度 3
	fmt.Println(len(twoD[0]))
}

实例7-切片

package main

import "fmt"

func main() {
// 使用make创建切片 用起来和数组挺像 但是不同于数组,它是可拓展的 
	s := make([]string, 3)
	s[0] = "a"
	s[1] = "b"
	s[2] = "c"
	fmt.Println("get:", s[2])   // c
	fmt.Println("len:", len(s)) // 3
// 这里便是特别之处 我们使用append方法向s后添加新元素
// 注意:append返回的是新的数组的指针 所以如果是要修改原来的内容记得赋值给自己
	s = append(s, "d")
	// 也可一次添加多个元素
	s = append(s, "e", "f")
	fmt.Println(s) // [a b c d e f]

	c := make([]string, len(s))
	// 复制 
	copy(c, s)
	fmt.Println(c) // [a b c d e f]
// 包前不包后 
	fmt.Println(s[2:5]) // [c d e]
	fmt.Println(s[:5])  // [a b c d e]
	fmt.Println(s[2:])  // [c d e f]

	good := []string{"g", "o", "o", "d"}
	fmt.Println(good) // [g o o d]
}

实例8-map映射

go中map映射是无序的

package main

import "fmt"

func main() {
	// map映射 键:值对 也是最常使用的数据结构
	m := make(map[string]int)
	// 和数组不同的是map映射可以用 "键" 来获取到 "值"
	m["one"] = 1
	m["two"] = 2
	fmt.Println(m)           // map[one:1 two:2]
	fmt.Println(len(m))      // 2
	fmt.Println(m["one"])    // 1
	fmt.Println(m["unknow"]) // 0
	// 这里尝试获取到一个未知的键值 返回两个值 一个是键对应的值 一个是是否存在(存在则true不存在则false) 
	r, ok := m["unknow"]
	fmt.Println(r, ok) // 0 false
	// 删除对应键的数据
	delete(m, "one")
// map 定义以及初始化
	m2 := map[string]int{"one": 1, "two": 2}
	var m3 = map[string]int{"one": 1, "two": 2}
	fmt.Println(m2, m3)
}

实例9-range语法

使得数组遍历时更为简单

package main

import "fmt"

func main() {
	// 对于一个 slice 或者一个 map 的话,我们可以用 range 来快速遍历,这样代码能够更加简洁。 
	// range 遍历的时候,对于数组会返回两个值,第一个是索引,第二个是对应位置的值。
	// 如果我们不需要索引的话,我们可以用下划线来忽略。
	nums := []int{2, 3, 4}
	sum := 0
	for i, num := range nums {
		sum += num
		if num == 2 {
			fmt.Println("index:", i, "num:", num) // index: 0 num: 2
		}
	}
	fmt.Println(sum) // 9

	m := map[string]string{"a": "A", "b": "B"}
	for _, v := range m {
		fmt.Println(v) //  A; B
	}
	for k := range m {
		fmt.Println("key", k) // key a; key b
	}
}

实例10-函数

package main

import "fmt"
// 函数 func 关键字标识 接下来是函数名 参数 返回值(特别的返回值可以是多个
func add(a int, b int) int {
	return a + b
}

func add2(a, b int) int {
	return a + b
}
// 大多是go函数都是会返回多个值的 第一个是正常的 第二个是错误信息
func exists(m map[string]string, k string) (v string, ok bool) {
	v, ok = m[k]
	return v, ok
}

func main() {
	res := add(1, 2)
	fmt.Println(res) // 3

	v, ok := exists(map[string]string{"a": "A"}, "a")
	fmt.Println(v, ok) // A True
}

实例11-指针

package main

import "fmt"
// 指针 我们首次见它是在c语言中
// 作为灵活易出错的家伙在go中却没有那么让人讨厌 它的用途被压缩了
func add2(n int) {
	n += 2
}
// 修改传入参数的问题 c语言里也是很经典的 不用指针的话会有新的副本产生 不会影响到原有的内容
func add2ptr(n *int) {
	*n += 2
}

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

实例12-结构体

package main

import "fmt"
// type 名字 struct
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(checkPassword2(&a, "haha")) // false
}

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

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

实例13-结构体方法

package main

import "fmt"

type user struct {
	name     string
	password string
}
// 把(结构体)放在func和函数名中间即可将其定义为结构体方法 对应的结构体实例可以用点号去使用该方法
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
}

实例14-错误处理

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"}}, "wang")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(u.name) // wang

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

实例15-字符串

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
	// 是否以子字符串结尾 Suffix - n.后缀  v.加…作后缀;把…附在后头
	fmt.Println(strings.HasSuffix(a, "llo"))              // true
	// 子字符串"首次"出现的位置 返回下标
	fmt.Println(strings.Index(a, "ll"))                   // 2
	// 将字符串切片{"he", "llo"}用连字符"-"连接成一个新字符串,返回结果为"he-llo"。
	fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
	// 将字符串a重复两次
	fmt.Println(strings.Repeat(a, 2))                     // hellohello
	// 将字符串a中所有字符"e"替换为字符"E"
	fmt.Println(strings.Replace(a, "e", "E", -1))         // hEllo
	// 按照分隔符"-"将字符串"a-b-c"分割成一个字符串切片
	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
	// 一个中文字符占三个长度 一个英文字符占一个长度
	b := "你好"
	fmt.Println(len(b)) // 6
}

实例16-字符串格式化

package main

import "fmt"

type point struct {
	x, y int
}
// 字符串格式化
func main() {
	s := "hello"
	n := 123
	p := point{1, 2}
	fmt.Println(s, n) // hello 123
	fmt.Println(p)    // {1 2}
// %v打印任意类型的变量
	fmt.Printf("s=%v\n", s)  // s=hello
	fmt.Printf("n=%v\n", n)  // n=123
	fmt.Printf("p=%v\n", p)  // p={1 2}
	// 详细一些
	fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
	// 再详细一些
	fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}

	f := 3.141592653
	fmt.Println(f)          // 3.141592653
	// 限制小数点
	fmt.Printf("%.2f\n", f) // 3.14
}

实例17-json

package main

import (
	"encoding/json"
	"fmt"
)
// 首先保证字段名首字母大写
type userInfo struct {
	Name  string
	Age   int `json:"age"`
	Hobby []string
}

func main() {
	a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
	// json.Marshal函数将a对象编码成JSON格式的字节数组buf。如果编码过程中出现错误,则会抛出panic异常。
	buf, err := json.Marshal(a)
	if err != nil {
		// 这是一种异常处理机制 出现严重错误时进行终止
		panic(err)
	}
	fmt.Println(buf)         // [123 34 78 97...]
	fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
// json.MarshalIndent函数对a对象进行编码,指定缩进格式为制表符("\t")。如果编码过程中出现错误,则会抛出panic异常。
	buf, err = json.MarshalIndent(a, "", "\t")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf))

	var b userInfo
	// json.Unmarshal函数将buf字节数组 解码/反序列化 成一个userInfo类型的变量b。如果解码过程中出现错误,则会抛出panic异常。
	err = json.Unmarshal(buf, &b)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}

实例18-时间

package main

import (
	"fmt"
	"time"
)

func main() {
	// 获取当前时间
	now := time.Now()
	fmt.Println(now) // 2023-07-30 21:05:59.8593027 +0800 CST m=+0.003543001
	// 自定义时间
	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
	// t2和t的时间差
	diff := t2.Sub(t)
	fmt.Println(diff)                           // 1h5m0s
	// diff是一个time.Duration类型的对象,可以使用其Minutes()和Seconds()方法分别获取分钟数和秒数,并打印出来。
	fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
	// 使用time.Parse函数将字符串"2022-03-27 01:25:36"解析为一个time.Time类型的对象t3。
	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
	// 使用time.Now().Unix()函数获取当前时间的Unix时间戳(以秒为单位),并将其打印出来。
	fmt.Println(now.Unix()) // 1690723167
}

实例19-strconv字符串转数字

package main

import (
	"fmt"
	"strconv"
)

func main() {
	// 转换字符串到数字
	// 64位浮点数
	f, _ := strconv.ParseFloat("1.234", 64)
	fmt.Println(f) // 1.234
	// 十进制 64位整形
	n, _ := strconv.ParseInt("111", 10, 64)
	fmt.Println(n) // 111
	/*
	这段代码将字符串"0x1000"解析为一个十六进制数,并将其转换为int64类型的数字。
	由于第二个参数指定了进制数为0,所以需要在字符串前面加上"0x",表示十六进制数。
	同时,第三个参数指定了基数为16,表示解析的是十六进制数。最终得到的n的值为4096。
	*/
	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
}

实例20-环境变量的获取和设置与外部命令的执行

package main

import (
	"fmt"
	"os"
	"os/exec"
)
// 环境变量获取和设置 外部命令的执行
// go run example/20-env/main.go a b c d
func main() {
	// 获取命令行参数
	fmt.Println(os.Args)           // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
	// 通过调用os.Getenv函数获取名为"PATH"的环境变量,并将其打印出来。
	fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
	// 通过调用os.Setenv函数将名为"AA"的环境变量设置为"BB",并立即生效。
	fmt.Println(os.Setenv("AA", "BB"))
/*
使用exec.Command函数创建一个名为"grep"的外部命令,并传入参数"127.0.0.1"和"/etc/hosts"。
然后,调用CombinedOutput方法执行该命令,并将输出结果存储在buf中。如果执行过程中出现错误,则会抛出一个panic异常。
最后,将buf转换为字符串并打印出来,得到的结果是"127.0.0.1       localhost"。
*/
// 这里实际上会报错 因为我这会儿的系统是win10 而不是linux
	// buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
// 换成本机的显示conda版本号的命令则是成功的
buf, err := exec.Command("conda", "--version").CombinedOutput()
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf)) // 127.0.0.1       localhost
}

实例21-并发

package main
// Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。
// goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
import (
	"fmt"
	"time"
)

func say(s string)  {
	for i:= 0; i < 5; i++ {
		time.Sleep(100*time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	// 使用 go 语句开启一个新的运行期线程
	// 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。
	// 同一个程序中的所有 goroutine 共享同一个地址空间。
	go say("world")
	say("hello")
}

实例22-通道

package main
// 通道(channel)是用来传递数据的一个数据结构。
// 通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。
// 操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
/*
ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据并把值赋给 v
*/
import "fmt"

func sum(s []int, c chan int)  {
	sum := 0
	for _,v := range s {
		sum += v
	}
	c <- sum
}

func main()  {
	s := []int{1,2,3,4,5,6}
// 声明通道的方式 --默认是不带有缓冲区的 发送端发送数据,同时必须有接收端相应的接收数据。
//	c := make(chan int)
// 带缓冲区 缓冲区可以暂存数据
 	c := make(chan int, 10)
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:],c)

	 x, y := <-c, <-c
	 fmt.Println(x, y, x+y)
}
/*
package main

import (
        "fmt"
)

func fibonacci(n int, c chan int) {
        x, y := 0, 1
        for i := 0; i < n; i++ {
                c <- x
                x, y = y, x+y
        }
        close(c)
}

func main() {
        c := make(chan int, 10)
        go fibonacci(cap(c), c)
        // range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
        // 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
        // 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
        // 会结束,从而在接收第 11 个数据的时候就阻塞了。
        for i := range c {
                fmt.Println(i)
        }
}
*/

控制读写权限

go func(c chan int) { //读写均可的channel c } (a)
go func(c <- chan int) { //只读的Channel } (a)
go func(c chan <- int) {  //只写的Channel } (a)

实例23-接口

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
接口可以让我们将不同的类型绑定到一组公共的方法上,从而实现多态和灵活的设计。
Go 语言中的接口是隐式实现的,也就是说,如果一个类型实现了一个接口定义的所有方法,那么它就自动地实现了该接口。因此,我们可以通过将接口作为参数来实现对不同类型的调用,从而实现多态。
package main

import "fmt"

type Phone interface {
	call()
}

type NokiaPhone struct {
	
}

func (nokiaPhone NokiaPhone) call() {
	fmt.Println("我是nok,我在叫你")
}

type IPhone struct {
	
}

func (iPhone IPhone) call() {
	fmt.Println("我是iPhone,我在叫你")
}

func main()  {
	var phone Phone

	phone = new(NokiaPhone)
	phone.call()

	phone = new(IPhone)
	phone.call()
}

你可能感兴趣的:(golang,实例,golang,开发语言,后端)