这篇文章上次修改于 1220 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
title: "golang.MD"
author: "andy"
description: "description information"
date: "2016-09-28"
lastmod: "2023-11-28"
【Golang】基础语法总结
一,关键字 (关键字25个)
break default func interface select case defer go map struct chan else goto
package switch const fallthrough if range type continue for import return var
二,数据类型
NUMBER,STRING, BOOLEAN ARRAYS,SLICES,MAPS
三,内置常量
true false iota nil
三,内建类型
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64 bool byte rune string error
三,内建函数
make len cap new append copy close delete complex real imag panic recover
close 用于channel 通讯。使用它来关闭channel
delete 用于在map 中删除实例。
len 和cap 可用于不同的类型, len 用于返回字符串、slice 和数组的长度.
new 用于各种类型的内存分配。
make 用于内建类型(map、slice 和channel)的内存分配。
copy 用于复制slice
append 用于追加slice。
panic 和recover 用于异常处理机制
print 和println 是底层打印函数,可以在不引入fmt 包的情况下使用。
complex、real 和imag 全部用于处理复数
四,变量声明
使用const关键字:const 常量名 常量类型 = 常量值
数组 声明格式:var 数组名 [元素个数]元素类型
var arr1 [5]int //具有5个int元素的数组,未进行初始化,元素默认为零值
var arr2 [5]int{1, 2, 3, 4, 5} //定义并直接初始化
切片 声明格式:var 切片名 []切片类型
var sic1 []int //声明含有多个未知元素的切片
var sic2 []int{} //声明空切片
结构体声明 type 结构体名 struct {}:右括号必须和type在同一行
枚举声明 使用iota+const关键字
const (
r = iota //0
s = iota //1
t = iota //2
)
const (
u = iota //0
v //1
w //2
)
const (
u1 = iota //0
v1, w1, x1 = iota, iota, iota //1, 1, 1
)
类型别名 type 类型别名 类型原名
for 初始条件; 判断条件; 条件变换 {
//TODO
}
range关键字的使用 作用:迭代遍历切片/数组中的每一个元素,默认有两个返回值,第一个为元素下标,第二个为元素数据
switch语句
golang保留break关键字,在switch语句中如果不写则默认添加
break可用于for/switch/select
continue只可以用于for
case后面可以跟多个条件
Go语言改进了 switch 的语法设计,case 与 case 之间是独立的代码块,不需要通过 break 语句跳出当前 case 代码块以避免执行到下一行
switch 中的表达式是可选的,可以省略。如果省略表达式,则相当于 switch true,这种情况下会将每一个 case 的表达式的求值结果与 true 做比较,如果相等,则执行相应的代码
//首先声明变量
var num1 int = 1
switch num1 {
case 1:
//...
case 2:
//...
case 3, 4, 5:
//...
...
default:
//...
}
//直接使用初始化语句
switch num2 := 1; num1 {
case 1:
//...
case 2:
//...
...
default:
//...
}
//switch后面可以不添加参数
var num int = 0
switch {
case num > 90:
//...
case num < 90:
//...
default:
//...
}
var name, sex, addr string = "andy", "man", "xian"
name := "string" (自动推导类型不可以写到函数外,作为全局变量)
numbers := make([]int, 5, 10)
var m map[string]int
m := make(map[string]int)
for key := range m {
delete(m, key)
}
data := map[string]string{"1": "A", "2": "B", "3": "C"}
for k, v := range data {
data[v] = k
fmt.Printf("res %v\n", data)
}
type Person struct {
Name string
Age int
}
func add(a int, b int) (c int) {
c = a + b
return
}
内置函数
Go 语言拥有一些不需要进行导入操作就可以使用的内置函数。它们有时可以针对不同的类型进行操作,例如:len、cap 和 append,或必须用于系统级的操作,例如:panic。因此,它们需要直接获得编译器的支持。
append -- 用来追加元素到数组、slice中,返回修改后的数组、slice
close -- 主要用来关闭channel
delete -- 从map中删除key对应的value
panic -- 停止常规的goroutine (panic和recover:用来做错误处理)
recover -- 允许程序定义goroutine的panic动作
real -- 返回complex的实部 (complex、real imag:用于创建和操作复数)
imag -- 返回complex的虚部
make -- 用来分配内存,返回Type本身(只能应用于slice, map, channel)
new -- 用来分配内存,主要用来分配值类型,比如int、struct。返回指向Type的指针
cap -- capacity是容量的意思,用于返回某个类型的最大容量(只能用于切片和 map)
copy -- 用于复制和连接slice,返回复制的数目
len -- 来求长度,比如string、array、slice、map、channel ,返回长度
print、println -- 底层打印函数,在部署环境中建议使用 fmt 包
数组和切片
Array 是同类型元素的数组。Array在声明的时候会指定长度且不能改变。定义一个固定长度为3的数组:
Slices 是能随时扩容的同类型元素的序列 。Slice的声明方式如下定义一个长度为0 的slices:
Slice 是数组的封装,其内部实现是数组,slice有三个元素,容量,长度和指向内部数组的指针。
Slice 的容量可以通过append 或者 copy函数增加。Append函数也能在数组的末尾添加元素,在容量不足的情况下会对slice扩容。
make和new
Go有两个数据结构创建函数:new和make。
new返回一个指向已清零内存的指针,而make返回一个复杂的结构。
基本的区别是 new(T) 返回一个 *T ,返回的这个指针可以被隐式地消除引用(图中的黑色箭头) 。而 make(T, args) 返回一个普通的T.
注意:空切片和 nil 切片是不同的,空切片指向的地址不是nil,指向的是一个内存地址,但是它没有分配任何内存空间,即底层元素包含0个元素。
不管是使用 nil 切片还是空切片,对其调用内置函数 append,len 和 cap 的效果都是一样的。
只有make能做的操作:
a.创建一个chan
b.创建一个内存预分配的map
c.创建一个内存预分配的slice,并且slice的len可以不等于cap
make用于内建类型(map、slice 和channel)的内存分配。new用于各种类型的内存分配。
内建函数new本质上说跟其它语言中的同名函数功能一样:new(T)分配了零值填充的T类型的内存空间,并且返回其地址,即一个T类型的值。用Go的术语说,它返回了一个指针,指向新分配的类型T的零值。有一点非常重要:new返回指针。
内建函数make(T, args)与new(T)有着不同的功能,make只能创建slice、map和channel,并且返回一个有初始值(非零)的T类型,而不是T。
本质来讲,导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如,一个slice,是一个包含指向数据(内部array)的指针、长度和容量的三项描述符;在这些项目被初始化之前,slice为nil。对于slice、map和channel来说,make初始化了内部的数据结构,填充适当的值。make返回初始化后的(非零)值。
make 是 引用类型 初始化的方法。
零值和特性
Go任何类型在未初始化时都对应一个零值:布尔类型是false,整型是0,字符串是"",而指针,函数,interface,slice,channel和map的零值都是nil。
golang 不是完全的面向对象语言,但是支持很多面向对象的特性,例如有结构体,接口,方法等。
bool类型不能转换为整型,整型也不能转换为bool类型,这种不能转换的类型叫做不兼容类型。
官方的go编译器限制channel最多能容纳到65535个元素
列表列表与切片和 map 不同的是,列表并没有具体元素类型的限制,因此,列表的元素可以是任意类型,这既带来了便利,也引来一些问题,
例如给列表中放入了一个 interface{} 类型的值,取出值后,如果要将 interface{} 转换为其他类型将会发生宕机。
container/list
nameList := list.New()
var nameList list.List
l.PushBack("fist")
l.PushFront(67)
go只提供了一种循环方式,即for循环,在使用时可以像c那样使用,也可以通过for range方式遍历容器类型如数组、切片和映射
c++ : 编译时生成每种类型的方法,缺点编译慢,需要后端消除无用代码
java: 类型擦除,所有类型都转换成Object,取值再做一次拆箱,缺点运行慢
移除原因
支持泛型的Go 1.18 Beta 1版本发布以来,围绕着constraints包的争议很多。
主要是以下因素,导致Russ Cox决定从Go标准库中移除constraints包。
constraints名字太长,代码写起来比较繁琐。大多数泛型的代码只用到了any和comparable这2个类型约束。
constaints包里只有constraints.Ordered使用比较广泛,其它很少用。所以完全可以把Ordered设计成和any以及comparable一样,
都作为Go的预声明标识符,不用单独弄一个constraints包。
在官方的最新proposal里有提到,在Golang中,并不是所有的类型都满足+号运算。
在go 泛型的版本中,泛型函数只能使用类型参数所能实例化出的任意类型都能支持的操作。
函数可以通过type关键字引入额外的类型参数(type parameters)列表:func F(type T)(p T) { ... } 。
这些类型参数可以像一般的参数一样在函数体中使用。
类型也可以拥有类型参数列表:type M(type T) []T。
每个类型参数可以拥有一个约束:func F(type T Constraint)(p T) { ... }。
使用interface来描述类型的约束。
被用作类型约束的interface可以拥有一个预声明类型列表,限制了实现此接口的类型的基础类型。
使用泛型函数或类型时需要传入类型实参。
一般情况下,类型推断允许用户在调用泛型函数时省略类型实参。
如果类型参数具有类型约束,则类型实参必须实现接口。
泛型函数只允许进行类型约束所规定的操作。
尽管最新的proposal冗长而详尽,但总结起来如下:
函数和类型可以具有类型参数,该类型参数使用可选约束(接口类型)定义,约束描述了这些参数所需的方法和允许的类型。
当使用类型参数调用函数时,类型推断通常会允许用户省略类型参数。
泛型函数只能使用约束允许的所有类型支持的操作
此设计完全向后兼容,但建议对func F(x(T))的含义进行更改。
func printSlice[T any](s []T) {
for _, v := range s {
fmt.Printf("%v ", v)
}
fmt.Print("\n")
}
func main() {
printSlice[int]([]int{1, 2, 3, 4, 5})
printSlice[float64]([]float64{1.01, 2.02, 3.03, 4.04, 5.05})
printSlice([]string{"Hello", "World"})
printSlice[int64]([]int64{5, 4, 3, 2, 1})
}
type Addable interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64, complex64, complex128,
string
}
func add[T Addable] (a, b T) T {
return a + b
}
func main() {
fmt.Println(add(1,2))
fmt.Println(add("hello","world"))
}
func mapFunc[T any, M any](a []T, f func(T) M) []M {
n := make([]M, len(a), cap(a))
for i, e := range a {
n[i] = f(e)
}
return n
}
func main() {
vi := []int{1, 2, 3, 4, 5, 6}
vs := mapFunc(vi, func(v int) string {
return "<" + fmt.Sprint(v*v) + ">"
})
fmt.Println(vs)
}
func findFunc[T comparable](a []T, v T) int {
for i, e := range a {
if e == v {
return i
}
}
return -1
}
func main() {
fmt.Println(findFunc([]int{1, 2, 3, 4, 5, 6}, 5))
}
没有评论
博主关闭了评论...