Featured image of post go语言-1

go语言-1

特性

  • go的语法简洁明了,易于学习和阅读便于学习。
  • 是一种编译型语言,go代码会被编译成机器码,执行效率高启动速度快
  • go天然支持高并发提供了goroutine来处理并发操作,channel用于goroutine之间的通信。go并发模型 基于“不要通过共享内存来通信,而是通过通信来共享内存”
  • 自带垃圾回收机制,降低了内存泄漏的风险
  • go鼓励使用组合而不是继承来组织和复用代码。它的结构体(structs)可以嵌入其他类型。

关键字(25个)

关键字 描述
break 用于终止当前循环
case switch 语句中的一个分支
chan 表示一个通道类型
const 定义常量
continue 跳过当前循环的剩余代码,开始下一次循环
default switch 或 select 语句中的默认分支
defer 延迟执行一个函数直到上层函数返回
else if 语句中的否则分支
fallthrough 在 switch 语句中强制执行下一个 case
for 循环语句
func 定义一个函数
go 启动一个新的 goroutine
goto 转到一个标签
if 条件语句
import 引入包
interface 定义一个接口
map 表示一个映射类型
package 定义一个包
range 迭代数组、切片、字符串、映射或通道
return 从函数中返回
select 选择不同类型的通讯
struct 定义一个结构体
switch 条件分支语句
type 类型定义或类型别名
var 定义一个变量

import

//导入单个包
import "fmt"
//导入多个
import (
    "fmt"
    "sync"
)

包管理

go默认采用go mod进行包管理

go mod init temp.github.com #初始化
go mod tidy #添加缺少的模块,移除不再需要的模块
go mod download #下载模块
go mod list #列出模块
go mod graph #打印模块依赖图

main函数

    package main
    import "fmt"

    func main(){
        //执行内容
    }

变量与常量

    //1.定义再赋值
	var name string
	name = "mikasa"
	//2.定义直接赋值
	var age = 10
	var gender = "man"
	fmt.Printf("name : %s,age : %d,gender:%s\n", name, age, gender)
    //3.自动推导赋值
	adress := "背景"
	fmt.Println("adress:", adress)
    //4.平行赋值
	i, j := 10, 20
	fmt.Println("i:", i, "j:", j)
	i, j = j, i//交换两个变量的位置
	fmt.Println("i:", i, "j:", j)
    //通过字符串创建了一个切片
	str11 := "abcdefljin"
	str22 := str11[2:4]
	fmt.Println(str22)
   //定义常量
	const conNum = 5
	const con string = "10"
	const (
		a = 1
		b = 2
	)

自增与自减

    //go里面没有 --i  ++i
	//只有i++ i-- 且必须只能独占一行
    i := 2
	i++
	i--

数组及遍历

for-range底层实现

for-range典型面试问题

1.

func main() {
	arr := []int{1, 2, 3}
	for _, v := range arr {
		arr = append(arr, v)
	}
	fmt.Println(arr)
}

$ go run main.go
1 2 3 1 2 3

2.

func main() {
	arr := []int{1, 2, 3}
	newArr := []*int{}
	for _, v := range arr {
		newArr = append(newArr, &v)
	}
	for _, v := range newArr {
		fmt.Println(*v)
	}
}

$ go run main.go
3 3 3
    //定义一个长度为10的数组
    nums := [10]int{1, 2, 3, 4}

    //数组的遍历方法1
	for i := 0; i < len(nums); i++ {
		fmt.Println("i:", i, "nums", nums[i])
	}
	//数组的遍历方法2
    //所有的 for-range 循环都会被转换成不包含复杂结构、只包含基本表达式的for语句
    //对于所有的 range 循环,Go 语言都会在编译期将原切片或者数组赋值给一个新变量 ha,在赋值的
    //过程中就发生了拷贝,而我们又通过 len 关键字预先获取了切片的长度,所以在循环中追加新的元素
    //也不会改变循环执行的次数
	for key, value := range nums {
		fmt.Println("key:", key, "value:", value)
	}
    //3.
    //在go语言如果想省略一个值可以用下划线_
	//如果两个值都想省略不能:=而用=
	for _, value := range nums {
		value += 1 //··
		fmt.Println("省略Key的value:", value)
	}
	for _, _ = range nums {
		fmt.Println("省略两个值:")
	}

    //4.数组传递
    var arr [5]int = [5]int{1, 2, 3, 4, 5}
	printArr(&arr) //数组是值类型默认是值传递 ,此处采用引用传递,函数修改后能影响源数据
	fmt.Println(arr)
   
   //函数结构数组的指针
   func printArr(arr *[5]int) {
	arr[0] = 10
	for _, v := range arr {
		println(v)
	}
}

指针

//go 语言也有指针 * 为取地址里面的值
//结构体成员调用 c语言 ptr->name  go语言 ptr.name
//go语言在使用指针时,会使用内部的垃圾回收机制gc(garbage collector),开发人员不需要手动释放内存
//c语言不许返回栈上的指针,go语言可以返回,程序在编译的时候就确定的指针的位置
//go语言在编译的时候,如果发现有必须要会将变量分配到堆上
//1.第一种定义指针
	name := "mika"
	ptr := &name
	fmt.Println("name:", name, "ptr:", ptr, "*ptr:", *ptr)
	//2.第二种定义指针
	age := new(int)
	fmt.Println("age:", age)
	*age = 10
	fmt.Println("*age:", *age)
    //可以返回栈上面的指针,因为在编译的时候,会自动判断,将city这个变量分配到堆上面
	ptr = test()
	fmt.Println("ptr:", ptr)

    // 定义函数返回一个指针,go语言函数的返回值写在后面
func test() *string {
	//作为局部变量函数执行完后应该会被释放
	city := "beijing"
	return &city
}

不支持的运算符

++i
--i
c=a>b?3:4 go语言不支持三目运算符三目运算符

0在go语言中不能表示逻辑 
if 0{

    fmt.Println(1)
}

字符串

    //1.定义
    var str string
    str = "aaa"
    name := "duke"
    //2.go语言按照原格式输入字符串加 ``
	usage := `
			sfds
		
			nsi
			`
    //3.字符串长度访问
	strLength := len(name)
    //4.拼接 使用strings.Builder 效率更高
	i := "mikasa : "
	j := "like"
	fmt.Println("字符串拼接:", i+j)
	//字符串截取 左闭右开
	fmt.Println("字符串截取:", i[2:])
	fmt.Println("字符串截取:", i[:2])
	fmt.Println("字符串截取:", i[1:3])
	//可直接使用字符串进行比较,使用ascii表
	if i > j {
		fmt.Println(2)
	}

枚举

const {
  BEIJING = iota //iota默认等于0
  SHANGHAI //iota=1
  SHENZHEN //iota=2
}

切片

//切片,它的底层也是数组,可动态的修改长度
	adress := []string{"北京", "上海", "广州", "深圳"}

	//追加元素
	adress1 := append(adress, "长沙")
    //2.对于切片不仅有长度的概念还有容量的概念  容量不够时为小于1024时翻倍增长
	for i := 0; i < 50; i++ {
		nums = append(nums, i)
		fmt.Println("len:", len(nums), "cap:", cap(nums))

	}

切片注意点

names := []string{"beijing", "shanghai", "shenzhen", "changsha"}

	//基于names创建一个数组
	names1 := [3]string{}
	names1[0] = names[0]
	names1[1] = names[1]
	names1[2] = names[2]

	//修改
	names1[2] = "深圳"
	fmt.Println("names:", names)   //
	fmt.Println("names1:", names1) //深圳

	//基于切片创建一个新数组,属于引用之前的数组,如果修改数据之前的数据也会发生改变
	names2 := names1[0:3]

	fmt.Println("修改前names1:", names1, "修改前names2:", names2)
	names2[2] = "广州"
	fmt.Println("修改后names1:", names1, "修改后names2:", names2)
	//1.如果从0开始截取,: 左边可以省略
	names3 := names[:2]
	fmt.Println("names3[:2]:", names3)
	//2.如果截取数组最后一个元素,冒号右边可以省略
	names3 = names[1:]
	fmt.Println("截取到最后一个元素names3[1:]:", names3)

	//3.如果截取所有元素,冒号左右都可以省略
	names3 = names[:]
	fmt.Println("截取所有元素[:]:", names3)
	//4.对字符串截取
	str := "abcd"
	s1 := str[1:]
	fmt.Println("字符串截取:", s1)

	//5.可以在创建空切片的时候,明确指定容量,这样可以提高运行效率
	//创建一个容量为20的切片,当前长度为0的string
	//make的时候,初始值类型都是对应的零值类型  bool -> false  字符串 -> 空  数字->0
	str2 := make([]string, 10, 20) //第三个参数不是必须 ,如果未填写容量则与长度相等
	fmt.Println("str2:", str2[0])
	if str2[0] == "" {
		fmt.Println("为空")
	}
	fmt.Println("str2-len:", len(str2), "str2-cap:", cap(str2))
	str2[0] = "hello"
	str2[1] = "world"

	//6.如果想让切片完全独立于原始数组,可以用copy()函数
	str3 := make([]string, len(str2))
	copy(str3, str2[:]) //str3完全独立于原始数组,修改后不会对原始数组产生影响
	str3[0] = "mikasa"
	fmt.Println("复制的str3:", str3, "原str2:", str2)

字典

    //1.定义一个字典,此时还不能赋值,因为还未初始化,它是空的
	var namesM map[int]string
    //2.分配空间,可以指定长度或者不指定长度,指定长度性能更好
	namesM = make(map[int]string)
	namesM[0] = "北京"
    //3.定义直接分配空间, nums:=make(map[int]string,10) 比较常用
    idNames := make(map[int]string)
    //4.字典遍历
	for k, v := range namesM {
		fmt.Println("k:", k, "v:", v)
	}
    //5.如何确定一个key 在mao中,mao不存在索引越界的问题
	fmt.Println("索引越界不会抛异常:", idNames[50]) //此句在go语言中不会抛异常
    value, ok := namesM[9] //如果当前map中存在该key,value的值为 0 ,ok返回true
    //6.删除map中的元素
	//使用自由函数delete在删除map中的元素
	fmt.Println("删除前idNames:", idNames)
	delete(idNames, 0)
  • Map不是线程安全的,如果遇到并发访问需要加锁
  • sync.Map 是并发安全的其内部默认加了互斥锁

函数

//1.函数的返回值在参数列表之后
//2.如果有多个返回值用圆括号包裹,用逗号分割
num := test1()
d, e, _ := test2() //不需要接受的返回值可以用下划线省略
fmt.Println(num)

// 多个返回值
func test2() (a int, b int, c string) {
	return 10, 20, "北京"
}

// 局部变量内存逃逸
func test4(str string) *int {
	num := 10
	return &num
}
Licensed under CC BY-NC-SA 4.0
本文总阅读量 次 本文总访客量 人 本站总访问量 次 本站总访客数
使用 Hugo 构建
主题 StackJimmy 设计