golang语法基础


此文章只做总结,以记住语法为准,学习go的同学应该都不是第一次学习编程语言了,既然玩了go,就要以生产实践为主。

导入

import “fmt”

起别名

import f “fmt”

批量导入,使用()来表示

import ( "fmt" "math" )

只导入不调用

import ( "fmt" _ "math" )

在go中禁止循环导入,无论直接还是间接,编译无法通过

导出

该规则适用于整个Go语言:对外暴露,首字母大写;不对外暴露,首字母小写

私有

go中约定,一个包内名为internal包为私有包,其他的包将无法访问私有包中的任何东西

数据类型

bool

true & false
在go中,整数0并不代表假值,非零整数也不能代表真值,即数字无法代替布尔值进行逻辑判断,两者是完全不同的类型

整型

uint8、uint16、uint32、uint64
int8、int16、int32、int64
uint、int
uintptr 等价于无符号64位整型

浮点型

float32、float64

字符类型

byte 等价于uint8表示ANSCII字符
rune 等价于int32表示Unicode字符
string 字节序列,可以转换为[]byte类型即字节切片

派生类型

数组 [5]int,长度为5的整型数组
切片 []float64,64位浮点数切片
映射表 map[string]int ,键为字符串类型、值为整型的映射表
结构体 type Gopher struct{} Gopher结构体
指针 *int 一个整型指针
函数 type f func(),一个参数,没有返回值的函数类型
接口 type Gopher interface{},Gopher接口
通道 chan int,整型通道

零值

数字类型 0
布尔类型 false
字符串类型 “”
数组 固定长度对应类型的零值集合
结构体 内部字段都是零值的结构体
切片、映射表、函数、接口、通道、指针 nil

常量

const 修饰的必须初始化的字面量、常量表达式

变量

var 修饰的

声明

只声明不赋值,则为零值

简单声明

var intNum int

同时声明相同的数据类型

var numA,numB,numC int

同时声明多个变量

var (
name string
age int
)

赋值

先声明再赋值

var name string
name = “jack”

声明直接赋值

var name string = “jack”

同时赋值多个变量

var name string
var age int
name,age = “jack”,1

语法糖

a := 1

特殊情况,允许编译通过

func main() {
	a := 1
	a, b := 2, 2
	fmt.Println(a)
	fmt.Println(b)
}

交换

func main() {
	num1, num2 := 10, 20
	num1, num2 = num2, num1
	fmt.Println(num1)
	fmt.Println(num2)
}

匿名变量

a, b, _ := 1, 2, 3

比较

类型必须相同
minVal := min(1, 2, -1, 1.2)

数组

go中的数组是值类型,而非引用,并不是指向头部元素的指针

初始化

// 声明
var nums [5]int
// 元素初始化
nums := [5]int{1,2,3}
// new函数获取一个指针
nums := new([5]int)

使用

fmt.Println(nums[0])
nums[0] = 1
// 元素数量
len(nums)
// 数组容量
cap(nums)

切割

左闭右开

nums :=[5]{1,2,3,4,5}
nums[1:]
nums[:5]
nums[2:3]

切片

初始化

var nums []int // 值
nums := []int{1,2,3} // 值
nums := make([]int,0,0) // 值
nums := new([]int) // 指针

使用

切片的使用和数组完全一样

append

package main

import "fmt"

func main() {
	nums := make([]int, 0, 0)
	nums = append(nums, 1, 2, 3, 4, 5, 6, 7, 8, 9)
	fmt.Println(len(nums), cap(nums))
}

插入元素

头插入

func main() {
	nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	nums = append([]int{-1, 0}, nums...)
	fmt.Println(nums)
}

中间插入
例如在i的位置插入

nums = append(nums[:i+1], append([]int{999, 999}, nums[i+1:]…)…)

尾部插入
nums = append(nums,99,100)

删除元素

从头部删除n个元素

nums = nums[n:]
fmt.Println(nums) //n=3 [4 5 6 7 8 9 10]

从尾部删除n个元素

nums = nums[:len(nums)-n]
fmt.Println(nums) //n=3 [1 2 3 4 5 6 7]

从中间指定下标i位置开始删除n个元素

nums = append(nums[:i], nums[i+n:]…)
fmt.Println(nums)// i=2,n=3,[1 2 6 7 8 9 10]

删除所有元素

nums = nums[:0]
fmt.Println(nums) // []

拷贝

copy

clear

clear会将切片内所有的值置为零值

清空切片

func main() {
	s := []int{1, 2, 3, 4}
    s = s[:0:0]
	fmt.Println(s)
}

字符串

在Go中,字符串本质上是一个不可变的只读的字节数组,也是一片连续的内存空间

字面量

普通字符串

支持转义、不支持多行书写

"这是一个普通字符串\n"
"abcdefghijlmn\nopqrst\t\\uvwxyz"

原生字符串

支持多行书写,不支持转义

访问

func main() {
	str := "hello world"
	fmt.Println(str[0])
	fmt.Println(str[0:4])
}

不支持修改

str[0]=‘a’

转换

func main() {
	str := "this is a string"
	// 字符串转切片
	bytes := []byte(str)
	fmt.Println(bytes)
	// 切片转字符串
	fmt.Println(string(bytes))
}

字符串的内容是只读的不可变的,无法修改,但是字节切片是可以修改的

func main() {
	str := "this is a string"
	// 字符串转切片
	bytes := []byte(str)
	fmt.Println(bytes)
	bytes = append(bytes, 96, 97, 98)
	// 切片转字符串
	fmt.Println(string(bytes))
}

提示:两种类型之间的转换都需要进行数据拷贝,其性能损耗会随着长度的增加而增长。

长度

字符串的长度,并不是字面量的长度,而是字节数组的长度

func main() {
	str := "中国人"
	fmt.Println(len(str))
}

拷贝

本质是字节切片的拷贝

func main() {
	var dst, src string
	src = "this is a string"
	desBytes := make([]byte, len(src))
	copy(desBytes, src)
	dst = string(desBytes)
	fmt.Println(src)
	fmt.Println(dst)
}

也可以使用string.clone函数,本质内部实现差不多

func main() {
	var dst, src string
	src = "this is a string"
	dst = strings.Clone(src)
	fmt.Println(src, dst)
}

拼接

+ 拼接

转为字节使用append添加

package main

import "fmt"

func main() {
	var str string = "hello world"
	bytes := []byte(str)
	bytes = append(bytes, "您好 世界"...)
	fmt.Println(string(bytes))
}

strings.Builder

以上两种的性能都很差,如果对性能有要求,使用strings.Builder

package main

import (
	"fmt"
	"strings"
)

func main() {
	builder := strings.Builder{}
	builder.WriteString("hello world")
	builder.WriteString("hello world")
	fmt.Println(builder.String())
}

遍历

func main() {
	str := "hello world 您好世界"
	for _, r := range str {
		fmt.Printf("%c", r)
	}
}

rune 本质上是int32的别名

映射表

一般来说,映射表数据结构实现通常有两种,哈希表和搜索树,区别在于前者无序,后者有序,在Go中,map的实现是基于哈希通,所以也是无序的

初始化

字面量

func main() {
	mp := map[int]string{
		0: "a",
		1: "b",
		2: "c",
		3: "d",
	}
	fmt.Println(mp)
}

make

func main() {
	mp := make(map[string]int, 8)
	mp["a"] = 1
	fmt.Println(mp)
}

访问

不存在,返回对应的零值

func main() {
	mp := make(map[string]int, 8)
	mp["a"] = 1
	fmt.Println(mp["b"])
}

访问方式

func main() {
	mp := make(map[string]int, 8)
	//mp["a"] = 1
	fmt.Println(mp["b"])

	if val, exist := mp["a"]; exist {
		// 如果存在
		fmt.Println(val)
	} else {
		// 如果不存在
		fmt.Println("mp['a'] not exist")
	}
}

删除

delete(mp,"a")

遍历

func main() {
	mp := map[string]int{
		"a": 1,
		"b": 2,
		"c": 3,
		"d": 4,
	}
	for k, v := range mp {
		fmt.Println(k, v)
	}
}

清空

clear(mp)

Set

Set是一种无序的,不包含重复元素的集合,Go中并没有提供类似的数据结构的实现,但是map的键正是无序且不能重复的,所以也可以使用map来替代set

func main() {
	set := make(map[int]struct{}, 10)
	for i := 0; i < 10; i++ {
		set[rand.Intn(100)] = struct{}{}
	}
	fmt.Println(set)
}

提示:一个空的结构体不会占用内存

并发安全

map并不是一个并发安全的数据结构,Go团队认为大多数情况下map的使用并不涉及高并发的场景,引入互斥锁会极大的降低性能,map内部有读写检测机制,如果冲突会触发fatal error
在这种情况下,需要使用sync.Map来替代。

指针

Go保留了指针,在一定程度上保证了性能,同时为了更好的GC和安全考虑,又限制了指针的使用

创建

func main() {
	num := 2
	p := &num
	fmt.Println(p)
}

解引用符号

  1. 访问指针所指向元素
  2. 声明一个指针
func main() {
	num := 2
	p := &num
	fmt.Println(*p)

	var numPtr *int
	numPtr = &num
	fmt.Println(*numPtr)

}

指针声明初始化

func main() {
   var numPtr *int = new(int)
   fmt.Println(*numPtr)

   numPtr1 := new(int)
   fmt.Println(*numPtr1)

}

new 和 make

  • new
  1. 返回值是类型指针
  2. 接收参数是类型
  3. 专用于给指针分配内存空间
  • make
  1. 返回值是值,不是指针
  2. 接收的第一个参数是类型,不定长参数根据传入类型的不同而不同
  3. 专用于给切片,映射表,通道分配内存

结构体

Go中抛弃了类与继承,同时抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法可以模拟出一个类。结构体可以存储一组不同类型的数据,是一种复合类型

声明

type Person struct {
	name string
	age int
}

对于相同类型的字段,如下声明

type Rectangle struct {
	height, width float32
}

注意:在声明结构体字段时,字段名和方法名不应该重复

创建

package main

import "fmt"

type Programmer struct {
	Name     string
	Age      int
	Job      string
	Language string
}
 
func main() {
	programmer := Programmer{
		Name:     "jack",
		Age:      42,
		Job:      "bash",
		Language: "python",
	}
	fmt.Println(programmer)

}

组合

在Go中,结构体之间的关系是通过组合来表示的,可以显式组合,也可以匿名组合,后者使用起来更类似于继承


import "fmt"

type Person struct {
	name string
	age  int
}

type Student struct {
	p      Person
	school string
}

type Employee struct {
	p   Person
	job string
}

func main() {
	student := Student{
		p:      Person{name: "jack", age: 18},
		school: "lili school",
	}
	fmt.Println(student.p.name)
}
type Person struct {
	name string
	age  int
}

type Student struct {
	Person
	school string
}

type Employee struct {
	Person
	job string
}

func main() {
	student := Student{
		Person: Person{name: "jack",age: 18},
		school: "lili school",
	}
	fmt.Println(student.name)
}

指针

对于结构体而言,不需要解引用就可以直接访问结构体的内容


type Person struct {
	name string
	age  int
}

func main() {
	p := &Person{
		name: "jack",
		age:  18,
	}
	fmt.Println(p.age)
}

标签

结构体标签是一种元编程的形式,结合反射可以做出很多奇妙的功能
标签是一种键值对的形式,使用空格进行分隔。
结构体的容错性很低,如果没能按照正确的格式书写结构体,那么将导致无法正常读写,但是编译时不会有任何报错

type Programmer struct {
	Name string `json:"name"`
	Age  int `json:"age"`
}

空间结构体

空间结构体没有字段,不占用内存空间,可以通过unsafe.SizeOf函数计算占用字节大小

func main() {
	type Empty struct {
	}
	fmt.Println(unsafe.Sizeof(Empty{}))
}

应用:例如 将map作为set来使用

基于上面的引用内容,golang基础语法学习可以参考以下几个步骤: 1. 首先,我们需要安装golang开发环境。你可以直接进入官网(https://go.dev/)下载并安装golang的解释器。 2. 接下来,我们可以开始学习golang语法。从上面的引用内容可以看出,golang语法和Java的结构很相似,所以如果你之前有Java编程的经验,可以借鉴一些类比来学习。但是即使你没有Java的经验,也不用担心,golang语法相对简单并且易于学习。 3. 另外,golang被称为“云计算时代的开发利器”,在使用过程中给人一种优雅、亲切、舒适的感觉。因此,在学习golang的过程中,你可能会发现它的语法设计和使用方式非常人性化。 综上所述,学习golang基础语法可以通过安装开发环境、参考Java的结构以及体验其优雅、亲切、舒适的特点来进行。希望这些信息能够帮助你开始学习golang基础语法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [一文看完golang基础语法](https://blog.csdn.net/qq_35889508/article/details/128125279)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值