网站开发自学流程,国内专门做旅游攻略的网站,微信软文推广怎么做,羽毛球赛事2023赛程Go的数据类型定义
//运行第一个程序package main
func main(){print(Hello World)
}在GO语言中#xff0c;一个程序只能有一个main包#xff0c;对应只能有一个main方法#xff0c;若无法满足这个条件#xff0c;编译时将会报错。注释方式与PHP相同 import的使…Go的数据类型定义
//运行第一个程序package main
func main(){print(Hello World)
}在GO语言中一个程序只能有一个main包对应只能有一个main方法若无法满足这个条件编译时将会报错。注释方式与PHP相同 import的使用 个人在使用import时按照自己的编写习惯依赖IDE的自动导包功能实现包的导入。若导入包后没有使用会编译出错。 // 使用 . 来实现省略调用
import . fmt// 在包前通过别名替代包名
import stdio fmt// 包前使用 _ 作用为只调取包的init方法
import _ xxx// 使用 () 实现多包导入
import (fmtos
)GO的可见性 GO通过大小写来判别函数或者变量的权限小写则为private大写为public 定义数据结构 GO定义数据类型比较有意思。在函数体内使用var定义的变量必须被使用否则编译报错申明外部变量没有限制 布尔类型 布尔类型只有true与false两个值不可用0与1替代 整形 int类型根据使用的平台自动判别32位还是64位可以手动定义指定的位数例如 int8/uint16定义了指定8位的int型/16位的无符号int型 浮点型 浮点型有float32/float64精确范围对应7/15位 复数类型 complex64/complex128 其他值类型 array struct string 引用类型 slice map chan 接口类型 inteface 函数类型 func // 定义单个变量
var hello Hello World//定义多个变量
var(num 321str haha
)//定义常量定义多个常量与变量的定义一样
const PI 3.14类型零值 零值不等于空值变量被声明为某种类型后的默认值通常情况下整型的默认值为0bool为falsestring为空字符串 类型别名的定义 利用type进行类型别名的定义 type(
chinese string
intMax int64
)变量声明与赋值 变量的声明格式var name type变量的赋值格式name value声明的同时赋值var name [type] value自身推断赋值var name value简写赋值(不可全局变量赋值使用) name : value类型转换 进行类型转换时需要进行显式转换并且需要保证两个不同的类型转换可以互相兼容 var a a
b : int(a)常量的定义问题 常量值在编译时已经确定所以右侧的数据需要使用常量或者内置函数变量不能进行常量的赋值。定义常量组时如果不进行数值的赋值将会将其数值赋值为其上行的数值。常量初始化规则定义了每一行的常量定义个数一致时默认上行数值下行初始化将进行否则报错。 常量的iota是常量计数器只在常量的表达式中使用。const中每新增一行常量声明将使iota计数一次 // 赋值b,c均为hello字符串赋值g,h为1,2
const(a hellobce,f 1,2g,h
)// 输出 c为2 f为5
const(a1bc iotadef iota
)
运算符
1、运算符的基本介绍
运算符是一种特殊的符号可以表示数据的运算赋值比较等
1算术运算符 2赋值运算符 3比较运算符 4逻辑运算符 5位运算符 6其他运算符 比较两个数的大小。
package leeimport fmtfunc Test(){a:101b:66if(ab){fmt.Printf(a大一些)}elsefmt.Printf(b大一些)
}
注意go语言不支持三元运算符
2、运算符的优先级 控制语句
if条件判断 if条件判断在布尔表达式里面可以定义变量并行赋值.变量的作用域只能作用在代码块里面. // 格式
if 布尔表达式{语句块
}else if 布尔表达式{语句块
}else{语句块
}// 定义i5 输出5,下面一句会编译出错
if i:5;i10{print(i)
}
print(i)循环控制 go可以使用for完成所有的循环操作,变量的作用域只能作用在代码块里面 //经典for循环结构
for i:1;i100;i{print(i)
}//单条件(while式)for循环结构
for true{print(进入死循环)
}// 无条件式
for {print(hello)
}switch语句 switch不需要使用break自动进行跳出若需要连续条件选择使用fallthrough。 // 常规操作
i : 3
switch i{case 1:print(1)case 2:print(2)case 3:print(3)default:print(4)
}// 在表达式中定义变量
switch i3; {case i1:print(1)case i2:print(2)case i3:print(3)default:print(4)
}// 使用fallthrough 输出2 3
i : 2
switch i{case 1:print(1)case 2:print(2)fallthroughcase 3:print(3)default:print(4)
}复制
跳转语句 goto break continue 三者均可以执行跳转。 goto用于调整执行位置。使用时注意标签的位置 break用于循环语句中跳出循环并开始执行循环之后的语句 continue不是跳出循环而是跳过当前循环执行下一次循环语句一般用于for 循环中触发for增量语句的执行。 //goto操作 这里输出 你好这里是跳转
START:print(你好这里是跳转)os.Exit(1)for i:1; i3;i {goto START}print(这里是测试是否跳转)// break操作 输出 跳出了循环start
START:for i:1;i2 ;i {break START}print(跳出了循环start)//continue操作 输出 2 4 6 8
for i:1;i10 ;i {if(i%2!0){continue}print(i)
}
数组 数组的定义格式 var name [n] type 。 数组赋值时两个不同长度变量无法进行赋值操作。 go语言中 数组是一个值类型使用时直接对值进行操作而不是地址引用。 两个长度相同的数组可以实现等于号判断。 //常规定义
var a [5]int
//简写
a:[2]int{1,2}
//索引赋值:将最后一个元素定义为5 其余为默认值
a:[20]int{19:5}
//自动判断数组长度定义,使用三个点 编译器将会自动判断长度赋值
a:[...]int{11:5}
//定义指针
var p *[5]int
//定义多维数组
var arr [2][3]int{}
arr : [2][3]int{}//GO语言冒泡排序
package main
import fmt
func main(){var a [5]int{5,9,4,1,6}num : len(a)for i:0;inum ;i {for j:i1;jnum ;j {if(a[i]a[j]){temp:a[j]a[j] a[i]a[i] temp}}}fmt.Print(a)
}
切片
一、切片的定义 在Go语言中切片(Slice)是数组的一个引用。 它会生成一个指向数组的指针并通过切片长度关联到底层数组部分或者全部元素。 切片还提供了一系列对数组的管理功能(append、copy)可以随时动态扩充存储空间并且可以被随意传递而不会导致所管理的数组元素被重复复制。 根据以上特征切片通常被用来实现变长数组而且操作灵活。 切片的数据结构原型定义如下
src/ pkg/ runtime/ runtime. h
struct Slice
{ //must not move anythingbyte* array; //actual dataunit32 len; //number of elementsunit32 cap; //allocated number of elements
};
由切片数据结构的原型定义可以看到它抽象为以下三个部分: 指向被引用的底层数组的指针。 切片中元素的个数。 切片分配的存储空间。 二、切片的声明与创建 切片声明与创建的方法有三种 1、基于底层数组创建 2、直接创建 3、使用make()函数创建。 1、基于底层数组创建
在创建切片时可以基于一个底层数组切片可以只使用数组的一部分元素或所有元素甚至可以创建一个比底层数组还要大的数组切片因为切片可以动态增长。创建切片的格式如下:
var sliceName [ ]dataType 说明 切片名的命名规则和变量名相同遵循标识符命名规则。 在创建切片时不要指定切片的长度。 切片的类型可以是Go语言的任何基本数据类型。 例如
var slice1 [] int 上例中定义了一个整型切片slicel注意不要指定切片长度如果指定了长度就成了定义数组了。当一个切片定义好以后如果还没有被初始化默认值为nil, 而且切片的长度为0。切片的长度可以使用内置函数len()获取还可以使用内置函数cap()获取切片的内存容量。
所以,当一个切片定义好以后还要对切片进行初始化,这样切片才可用。对于上例,假如已经定义了一个整型数组array1,则切片slice1的初始化方式如下:
slice1 array1[start : end] 从上式可以看到,Go语言支持以array1[start : end]的方式基于一个底层数组来生成切片即切片引用的数组元素由array1[start]到 array1[end]但不包含array1[end]。
如果要引用底层数组的所有元素可采取的方式如下
slicel array1
slice1 array1[ :]
slicel array1[0: len(array1)]
2、直接创建切片
直接创建切片即在定义切片的时候初始化切片元素例如
var slice1 []int{1,2,3,4,5}
3、使用make函数创建切片
内置函数make()用于灵活的创建切片
var slicel make([]int,5)
上式创建了一个有5个元素的整型切片slicel,元素的初值为0。 在使用make()函数创建切片时还可以为切片元素预留存储空间。例如
var slice1 make([]int, 5,10)
上式表示创建整型切片slice1,元素个数为5,元素初值为0,并预留10个元素的存储空间。
三、切片元素的访问与遍历
切片元素的遍历和数组元素的遍历一样,要通过元素下标访问另外也可以使用关键字range遍历所有切片元素。切片元素访问的一般格式如下:
sliceName [sliceIndex]
遍历同数组使用range关键字表达式有两个返回值第一个是元素的下标第二个是元素的值。
四、切片的操作
1、切片元素的增加 可以使用append()函数向切片尾部添加新元素,这些元素保存到底层数组。append并不会影响原来切片的属性,它返回变更后新的切片对象。 与数组相比,除了都有长度(length)以外,切片多了一个容量(capacity)的概念,即切片中元素的个数和分配的存储空间是两个不同的值。如果在增加新元素时超出cap的限制则底层会重新分配一块“够大”的内存一般来说是将原来的内存空间扩大二倍,然后再将数据从原来的内存复制到新的内存块。
2、切片元素的复制 使用切片长时间引用“超大”的底层数组会导致严重的内存浪费。可以新建一个小的slice对象,然后将所需的数据复制过去。函数copy()可以在切片之间复制元素能够复制的数量取决于复制方和被复制方的长度值,通常取最小值。需要注意的是,在同一底层数组的不同切片间复制元素时,元素位置会发生重叠。
//切片的复制
package mainimport(fmt
)func main() {var slicel []int{1,2,3,4,5,6,7,8,9,10}var slice2 make([ ] int,3, 5)var n int//只能复制三个元素n copy(slice2,slice1)fmt. Println(n, slice2, len( slice2), cap(slice2))//slice3和slice1指向同一底层数组slice3 : slice1[3:6]//复制后元素重叠n copy(slice3, slice1[1:5])fmt.Println(n, slicel, slice3)
}
编译并运行程序输出结果为3 [1 2 3] 3 5
3 [1 2 3 2 3 4 7 8 9 10] [2 3 4] 通过输出结果可以看出在将slice1复制到slice2时由于slice2的长度最小为3所以只能将slice1的前三个元素复制给slice2。而将slicel1复制到slice3 时由于slicel1和slice3指向同一个底层数组所以复制后元素重叠。slice3刚创建时它引用的是底层数组的[4,5,6]三个元素,复制后slice1将[2,3,4]三个元素复制给slice3 ,所以最后slice3 的元素[2,3,4]覆盖了slice1的元素[4,5,6]。
3、排序和搜索切片 标准库中的sort包提供了对整型、浮点型和字符串类型切片进行排序的函数,检查一个切片是否排序好的函数以及使用二分搜索算法在一个有序切片中搜索-一个元素的函数。 同时提供了通用sort.Sort ()和sort.Search ()函数可用于任何自定义的数据。这些函数在表4-2中有列出。
函数
1.简介
函数为完成某一功能的程序指令语句的集合在Go中函数分为自定义函数、系统函数
2.基本语法
func 函数名(形参列表) (返回值列表) {函数体return 返回值列表
}3.递归
函数体内调用自己
package mainimport fmtfunc test(n int) {if n 2 {n--test(n)}fmt.Println(n , n)
}func main() {test(4)
}执行一个函数时就创建一个新的受保护的独立空间函数的局部变量是独立的不会相互影响递归必须向退出递归的条件逼近否则就会出现无限递归当一个函数执行完毕或者遇到return就会返回遵守谁调用就将结果返回给谁。
4.递归练习
1.求第N个斐波那契数列对应的值
package mainimport fmtfunc feb(n int) int {if n 2 {return 1}return test(n-1) test(n-2)
}func main() {result : feb(6)fmt.Println(result)
}2.已知函数f(1) 3f(n) 2*f(n-1) 1求f(n)的值
package mainimport fmtfunc test(n int) int {if n 1 {return 3}return 2*test(n-1) 1
}func main() {result : test(6)fmt.Println(result)
}
3.有一堆桃子猴子第一天吃了其中的一半并在多吃了一个以后每天猴子都吃其中的一半然后再多吃一个。当到第十天准备吃时发现只剩了1个桃子。问题最初总共多少个桃子 从上图可以看出其通项公式为(1 f(n1))* 2n代表天数
package mainimport fmtfunc getPeach(n int) int {if n 10 {return 1}return (1 getPeach(n1)) * 2
}func main() {result : getPeach(1)fmt.Println(result)
}5.函数使用注意细节 1.函数的形参列表和返回值列表都可以是多个 2.形参列表和返回值列表都可以是值类型或引用类型 3.函数命名遵循标识符命名规则首字母不能是数字首字母如果是大写则可以被其他文件或包调用否则只能在当前文件被调用 4.函数的变量是局部的函数外不生效 5.基本类型和数组默认都是值传递即进行值拷贝在函数内修改不会影响到原来的值 6.如果希望函数内的变量能修改函数外的变量可以传递变量的地址函数内以指针方式操做变量 7.Go函数不支持重载即一个包下不允许存在同名的函数 8.在Go语言中函数也是一种数据类型可以赋值给一个变量则该变量就是一个函数类型的变量通过该变量可以对函数进行调用 9.函数既然是一种数据类型因此在Go语言中函数可以作为形参并且调用 package mainimport fmtfunc test(myFunc func(int, int) int, num1, num2 int) int {return myFunc(num1, num2)
}func getSum(a, b int) int {return a b
}
func main() {resp : test(getSum, 1, 2)fmt.Println(resp)
}10.为了简化数据类型定义Go语言支持自定义数据类型 基本语法type myInt intmyInt就可以当作int类型来使用但不完全一致不能将一个myInt类型的值直接赋值给int类型的变量需要使用int()来强转一下。也可以使用type来定义一个函数类型package mainimport fmttype myFuncType func(int, int) intfunc test(myFunc myFuncType, num1, num2 int) int {return myFunc(num1, num2)
}func getSum(a, b int) int {return a b
}func main() {resp : test(getSum, 1, 2)fmt.Println(resp)
}11.支持对函数返回值命名 package mainimport fmttype myFuncType func(int, int) intfunc test(myFunc myFuncType, num1, num2 int) int {return myFunc(num1, num2)
}// 将函数返回值重命名为sum
func getSum(a, b int) (sum int) {sum a breturn
}func main() {resp : test(getSum, 1, 2)fmt.Println(resp)
}12.使用_来忽略返回值 13.Go支持可变参数参数名 ...必须放在参数最后位置 package mainimport fmtfunc getSum(args ...int) int {sum : 0for i : 0; i len(args); i {sum args[i]}return sum
}
func main() {resp : getSum(1, 2, 3)fmt.Println(resp)
}6.init函数
每个源文件都可以包含一个init函数该函数会在main函数前执行被Go运行框架调用。通常在init函数中完成初始化工作每个文件都可以有一个init函数 package mainimport fmtfunc init() {fmt.Println(init函数自动执行)
}func main() {fmt.Println(开始执行主函数)
}如果一个文件中同时包含全局变量、init函数、main函数则执行顺序为全局变量 init main package mainimport fmtvar money test()func test() int {fmt.Println(test())return 100
}func init() {fmt.Println(init函数自动执行)
}func main() {fmt.Println(开始执行主函数...money, money)
}// test()
// init函数自动执行
// 开始执行主函数...money 1007.匿名函数
Go支持匿名函数如果我们某个函数只希望使用一次可以考虑使用匿名函数匿名函数可以实现多次调用示例一在定义时就调用 package mainimport fmtfunc main() {res : func(n1, n2 int) int {return n1 n2}(10, 20)fmt.Println(result , res)
}示例二将匿名函数赋值给一个变量函数变量再通过该变量来调用匿名函数 package mainimport fmtfunc main() {sum : func(n1, n2 int) int {return n1 n2}res : sum(10, 20)fmt.Println(result , res)
}示例三全匿名函数将函数赋值给一个全局变量就成为一个全局函数可以在程序有效 package mainimport fmtvar multi func(n1, n2 int) int {return n1 * n2
}func main() {res : multi(10, 20)fmt.Println(result , res)
}8.闭包 闭包就是一个函数和与其相关的引用环境组合的一个整体 闭包必须满足三个条件 1、必须有一个内嵌函数 2、内嵌函数必须引用外部函数中的变量 3、外部函数返回值必须是内嵌函数 闭包可以使得变量常驻内存 package mainimport fmtfunc Closure() func(int) int {var n1 10return func(n2 int) int {n1 n1 n2return n1// return n1 n2 // 这样的结果完全不一样, n1 n1 n2会修改局部变量n1的值如果直接返回n1 n2则不会修改局部变量n1的值}
}func main() {res : Closure()fmt.Println(result , res(30)) // 40fmt.Println(result , res(31)) // 71
}nodejs function closure() { var a 10; function inner(b) {a a b; return a} return inner;
}
var func closure();
console.log(func(30)); // 40
console.log(func(31)); // 71python # 变量 a 对于 inner来说是外部变量因此不能直接进行修改
def closure():a 10def inner(b):a a breturn areturn inner# UnboundLocalError: local variable a referenced before assignment# 但对于inner来说是可以直接使用的
def closure():a 10def inner(b):return a breturn inner# 必须使用 nonlocal 来修改变量a的作用域从而对其进行操做
def closure():a 10def inner(b):nonlocal aa a breturn areturn innerfunc closure()
print(func(30)) # 40
print(func(31)) # 71案例使用闭包方式实现检查文件后缀名是否为.jpg如果不是则内部实现拼接.jpg否则直接返回 package mainimport (fmtstrings
)func Closure(endFix string) func(string) string {return func(name string) string {if strings.HasSuffix(name, endFix) {return name}return name endFix}
}func main() {res : Closure(.jpg)fmt.Println(result , res(aaa.jpg))fmt.Println(result , res(bbb))
}9.函数参数传递
值类型基本数据类型int系列、float系列、bool、string、数组、结构体引用类型指针、slice切片、map、管道chan、interface等 结构体
结构体是一种用户自定义的数据类型它由一组字段组成每个字段可以是任意基本类型或其他结构体类型。结构体在Go语言中被广泛使用它可以用来表示复杂的数据结构比如二叉树、链表、图等。
一个简单的结构体定义如下
copy codetype Person struct {name stringage intgender string
}
上面的代码定义了一个名为Person的结构体它有三个字段分别是name、age和gender它们的类型分别为string、int和string。我们可以通过该结构体来表示一个人的基本信息。
1.结构体的语法
Go语言中结构体的语法非常简洁它的基本形式如下
copy codetype 结构体名 struct {字段1 类型1字段2 类型2...字段n 类型n
}
其中结构体名是用户自定义的标识符用于表示该结构体的类型。字段是结构体中的成员每个字段都有一个对应的类型。在定义结构体时可以使用任何基本类型或其他结构体类型作为字段的类型。另外结构体中的字段可以使用大写字母开头的标识符表示公有成员小写字母开头的标识符表示私有成员。
2.结构体的初始化
在Go语言中结构体类型的变量可以通过结构体字面量来进行初始化。结构体字面量是一种简洁的语法可以用于快速创建一个结构体类型的变量。结构体字面量的基本形式如下
copy codevar 变量名 结构体类型{字段1: 值1,字段2: 值2,...字段n: 值n,
}
其中变量名是结构体类型的变量名结构体类型是用户自定义的结构体类型字段是结构体中的成员值是该成员对应的初始化值。我们可以省略字段名只提供值此时Go语言会按照结构体定义时的字段顺序来进行初始化。例如
copy codevar p1 Person{张三,18,男,
}var p2 Person{name: 李四,age: 20,gender: 女,
}
上面的代码分别创建了两个Person类型的变量p1和p2它们的字段值分别为{张三 18 男}和{李四 20 女}。可以看出结构体字面量提供了一种简单、直观的方式来初始化结构体类型的变量。
3.结构体的访问
在Go语言中我们可以通过结构体变量的字段名来访问结构体中的成员。例如
copy codevar p Person
p.name 张三
p.age 18
p.gender 男
上面的代码创建了一个名为p的Person类型的变量并对其成员进行了赋值。可以看出访问结构体成员的语法非常简单只需要使用点号.连接结构体变量和成员名即可。
4.结构体的方法
Go语言中的结构体还支持方法方法是一种特殊的函数它可以与结构体类型关联。方法与函数的区别在于方法必须在结构体类型上定义而函数可以在任何地方定义。另外方法可以访问结构体的成员而函数只能访问其参数。
Go语言中的方法定义如下
copy codefunc (接收者变量 接收者类型) 方法名(参数列表) 返回值列表 {// 方法体
}
其中接收者变量是一个标识符用于表示方法所属的结构体类型的变量。接收者类型是方法所属的结构体类型参数列表和返回值列表与普通函数的定义方式相同。
下面是一个例子
copy codetype Rectangle struct {width, height float64
}func (r Rectangle) Area() float64 {return r.width * r.height
}func main() {r : Rectangle{3, 4}fmt.Println(面积, r.Area())
}
上面的代码定义了一个名为Rectangle的结构体它有两个字段width和height。该结构体还定义了一个名为Area的方法用于计算矩形的面积。在main函数中我们创建了一个Rectangle类型的变量r并调用其Area方法来计算面积。
5.结构体的嵌套
在Go语言中结构体可以嵌套在其他结构体中从而形成更复杂的数据结构。嵌套结构体的定义方式与普通结构体的定义方式相同只是在字段的类型中指定另一个结构体类型。
下面是一个例子
copy codetype Address struct {Province stringCity string
}type Person struct {Name stringAge intAddress Address
}func main() {p : Person{Name: 张三,Age: 18,Address: Address{Province: 广东省,City: 深圳市,},}fmt.Println(p)
}
上面的代码定义了两个结构体类型Address和Person。Person结构体中包含一个Address类型的字段用于表示该人员的地址信息。在main函数中我们创建了一个Person类型的变量p并对其成员进行了赋值。可以看出嵌套结构体提供了一种简单、灵活的方式来表示复杂的数据结构。
6.结构体的匿名字段
在Go语言中结构体还支持匿名字段。匿名字段是一种特殊的字段类型它没有字段名只有字段类型。在结构体中可以使用匿名字段来表示继承关系或者组合关系。
下面是一个例子
copy codetype Person struct {stringint
}func main() {p : Person{张三, 18}fmt.Println(p.string, p.int)
}
上面的代码定义了一个Person结构体它包含了一个string类型的匿名字段和一个int类型的匿名字段。在main函数中我们创建了一个Person类型的变量p并对其成员进行了访问。可以看出使用匿名字段可以在一定程度上简化代码。
7.结构体的标签
在Go语言中结构体的字段可以使用标签tag来进行注释或者元数据的传递。标签是一个字符串它的格式为key:value其中key表示标签的名称value表示标签的值。
下面是一个例子
copy codetype Person struct {Name string json:nameAge int json:age
}func main() {p : Person{张三, 18}b, _ : json.Marshal(p)fmt.Println(string(b))
}
上面的代码定义了一个Person结构体它有两个字段Name和Age。在Name字段和Age字段上我们使用了json标签用于指定json序列化时使用的字段名。在main函数中我们创建了一个Person类型的变量p并将其序列化为json字符串。可以看出使用标签可以方便地进行元数据传递和注释。
8.结构体的应用场景
在Go语言中结构体被广泛应用于各种数据结构的定义和实现。下面是一些常见的应用场景
数据库ORM结构体可以与数据库表进行映射从而实现对象关系映射ORM功能。网络编程结构体可以用于表示网络数据包的格式从而实现网络编程功能。并发编程结构体可以用于实现并发编程模型例如管道、锁和条件变量等。配置文件结构体可以用于表示配置文件的格式从而实现配置文件读写功能。模板引擎结构体可以用于表示模板数据从而实现模板引擎功能。