Go语言基础(一)

本文是Go语言的基础教程,涵盖了环境搭建、编码规范、数据类型、运算符、流程控制、生成随机数、函数、内置函数、结构体、封装、继承、接口和空接口等内容。介绍了Go语言的安装、常用数据类型如布尔、字符串、数字和指针,以及流程控制语句和函数的使用方法。此外,还讨论了Go语言的封装特性和接口实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境搭建

  1. 下载去官方下最新稳定版本就好https://golang.google.cn/

  2. windows直接下一步就好,linux下载压缩包,官方建议下到/usr/local/下面然后解压tar -zvxf

  3. linux把环境变量添加到/etc/profile里面,然后source一下就能即刻生效

    vim /etc/profile
    	// 在最后一行添加
    	export GOROOT=/usr/local/go
    	export PATH=$PATH:$GOROOT/bin
    	export GOPATH=/root/go           #项目工作目录,这个是自己确认的
    	// wq保存退出后source一下
    source /etc/profile
    
  4. 环境变量解释,设置完成后检验,就是cmd下执行go version看看

    GOROOT	是go语言安装的位置
    GOPATH	是go语言写的源码文件夹,也既是我们平时说的工程项目目录,如果多个;隔开。GOPATH 工作空间是一个目录层次结构,其根目录包含三个子目录:
    		src:包含 Go 源文件,注意:你自己创建依赖的package,也要放到GOPATH 目录下,这样才能够被引用到。
    		pkg:是用来存编译好的库文件
    		bin:包含可执行命令
    Path	在户变量里面修改,是cmd界面下寻找命令的路径(建议用%GOROOT%\bin;%GOPATH%\bin)
    
  5. go语言的IDE建议用goland

  6. 注释单行用//,多行 /* 注释内容 */

  7. 编译是用go build,直接go build是编译当前文件夹(此时文件夹内有且只能有一个属于package main)。或者用go build xxx.go单独编一个文件此时没啥限制

编码规范

  1. 变量以字母、下划线、数字组成,区分大小写,不能包含标点等特殊符号,必须以字母或者下划线开头。

  2. 在go语言中,以大写字母开头的变量可以被外部包调用有点像public,小写有点像private

  3. 标准变量声明格式var 变量名 变量类型 = 初始值或表达式

  4. 常量 const 标识符 类型=值,常量不允许被修改,值只能是布尔,数字,浮点,字符串类型。iota是系统中常量的计数器,系统中有1个常量就加1,每一次const都会重新重置为0

    var a int = 100
    var b string = "abc"
    var c bool = false
    var d [3]int	定义一个名为d的数组,数组中元素为整形
    var e func() string	定义一个名为e的函数,返回值为字符串类型
    在函数内定义我们一般使用 k := 100 这样的缩写方式,只能在函数内这样使用
    单行注释//
    多行注释/*	……	*/
    字符串类型可以用+拼接起来
    

数据类型

  1. 布尔型
    布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true
  2. 字符串
    字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。如果有多行字符需要原样输出用键盘数字1前面的反引号2个。字符串的基本操作函数有strings和strconv
var x string = "abc你是傻逼吗,傻逼傻xxoo逼臭傻逼!"	//定义一个变量x
k := x[0]
//定义一个变量k,是x变量的第一个字符,如果是[6]代表第7个字节,索引从0开始
fmt.Println(k)	//此时K是97,类型是uint
fmt.Println(string(k))	//此时打印a

l := x[:3]
fmt.Println(l)	//此时打印abc
可以看出字符串截取的时候如果都是英文,截取出来的单个字符是数字需要转换,多个字符
直接是字符串,当有中文和英文混杂时,一般先把字符串转换成[]rune(x)

var flag = 0
func main() {
m := []rune(x)	//此时m是一个类型为rune的切片
	for _,arg := range m{
		if string(arg)=="傻" {
			flag ++
		}
	}
	fmt.Println(flag)
}

另外strconv是字符串与其他类型转换的函数,具体见文档
strconv.FormatInt()	格式化int,转为string
strconv.ParseaInt()	分析字符串,转为int
  1. 数字类
    整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码,int有int8(-128-127),int16,int32,int64等等,uint是没有符号的
  2. 指针类型(Pointer)
    形象点就是指向存储数据内存空间的那个针头(指针就是地址),go语言当中这个先简单了解下就好了
x := 18
fmt.Println(&x)	//&n就是n这个变量的内存地址的意思
此时&n类型*int*是指针,int表示这个指针是int类型数据的指针
p := &x
此时p是指针类型,值是指向x的内存地址,而&p是P这个变量本身的内存地址
在指针类型前面加上 * (前缀)来获取指针所指向的内容
  1. 数组类型(array),数组是一组相同类型数据的集合,长度已经被固定,元素可以被修改。这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。

    var a [4] int	定义了一个数组名字为a 长度是4,它的下标0-3
    也可以这样定义 var b = [4]int{1,2,3,4} 直接赋值了
    
    数组的遍历,如下示例,index如果换成_就是把取到的值舍弃掉,没用的话
    	for index,var := a
    		fmt.Println(index,var)
    注意数组是值类型数据,=的时候传递的是数组,并不是引用类型
    数组排序是使用自己编写的函数,最经典的是冒泡排序,就是左右值对比
    
    多维数组
    arry2 :=[3][4]int({},{},{}}
    [3]代表3个一维数组,[4]代表每个数组有4个元素,此时len()得到的是3代表
    3个一维数组
    
  2. 切片类型(slice),切片是个引用类型(指针),内部结构包含地址,大小,容量。数组不能更改元素个数,切片可以无限制的放。

    切片的定义是 var  s2 []int,跟数组很像,但是一定记住不要在[]写数字
    通常情况下,比较常用make函数来创建引用类型数据。
    s1 := make([]int,3,4)	创建一个切片,里面存在3个数据,切片长度是4
    所以我平时使用m :=make([]string,0,0)
    
    切片要在最后新增数据用append()函数,如下
    s1 := []int{1,2,3,4,5}
    s2 := []int{6,7,8,9,10}
    s3 := append(s1,s2...)	#注意这里是在s1末尾增加数据,由于s2是切片,
    增加的是切片里的内容所以用...
    fmt.Println(s3)
    结果[1 2 3 4 5 6 7 8 9 10
    
    copy函数
    copy(des,src)
    常用来切片的拷贝,将src的数据拷贝到des中,注意角标是一一对应的,如果src
    长度大于des,只会修改des中原有长度的值
    
  3. Map 类型(映射)
    引用类型,有点像python当中的字典,是无序的。var a map[string]int定义了一个map变量a,这是常规的定义,没有初始化。初始化使用make,k := make(map[string]int,10),加值k[“语文”]=100,k[“数学”]=98。也可以一步到胃,var k = map[string]int{"英语":70,"体育":80}

    func main(){
    	k:=map[string]int{"语文":100,"数学":80,"英语":90}
    	fmt.Printf("k的值是%#v\n",k)
    	value,ok := k["体育"]
    	fmt.Println(value,ok)
    }
    # 如果k的里面有英语这个key,把key对应的值赋予value,返回true给OK,这是
    一个特殊写法
    
    删除用delete()函数
    delete(m,)
    
    for subject ,v= range k{
    	fmt.Println(subject,v)
    }
    # 遍历k
    
    如果要删除map中的键值对就使用内置函数delete函数
    delete(map,key)
    
    g := make([]map[string]string)	创建一个切片g,切片里面的元素是map类型,
    key是string,值是string
    
  4. 结构体类型(struct)
    结构体看Go面向对象

  5. 接口类型
    同上

  6. Channel 类型

  7. 函数类型

格式化输出和输出

fmt.Printf

  • %T 变量的数据类型

  • %v 变量的值

  • %c 变量以对应的Unicode字符输出

  • %b 变量二进制

  • %d 变量十进制

  • %x 变量十六进制,a-f

  • %X 变量十六进制,A-F

  • %.2f 变量浮点表示,精度小数点后2位
    fmt.Sprintf(“%b”,a) 变量a转换成二进制,并返回

  • %s 变量字符串不带双引号

  • %q 变量字符串带双引号

  • \n 换行符

    var x int
    var y string
    fmt.Scanln(&x, &y)	
    fmt.Println(x, y)
    
    格式化输入需要使用&变量,这样是使用变量地址,可以理解为输入2个变量,
    把两片地址空间分别存入这个变量
    

运算符

基本与其他语言差不多,可以看这里菜鸟教程

流程控制

  • if,下面是个多选择语句,需要注意顺序,只会匹配一个if,可以嵌套。嵌套是把嵌套语句写在{}里面,这样两个if变成了与的关系

    func Judge() {
    	var score int = 71
    	if score >= 90 {
    		fmt.Println("成绩优秀")
    	}else if score >= 80 {
    		fmt.Println("成绩良好")
    	}else if score >= 70 {
    		fmt.Println("成绩中等")
    	}else {
    		fmt.Println("考成这B样还好意思问")
    	}
    }
    
  • switch,用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止,已经优化过不需要break。注意case 后面的判断值(可以是多个)是否相等(实例1),或者不写如下面(实例2)。如需强制执行下一个分支(仅仅一个)的语句需要在case分支后面最后一行加fallthrough(贯穿)。特别注意switch var1与case分支中的var类型必须一致

    var score int = 90
    switch score {
    case 90:
    	fmt.Println("你好棒啊")
    case 80:
    	fmt.Println("不错继续加油")
    }
    
    var score int = 90
    switch {
    case score >= 90:
    	fmt.Println("你好棒啊")
    case score >= 80:
    	fmt.Println("不错继续加油")
    }
    
  • for,go语言就一种循环下图实例100以内3倍数的相加的和

    func main() {
    	result := 0
    	for i:=0;i<=100;i++{
    		if i%3 == 0{
    			result +=i
    		}
    	}
    	fmt.Println(result)
    }
    i:=0 初始化参数,这样i的可用域只在循环体内,i<=100判断,注意这里只能是布尔类型,
    i++是执行完表达式后初始参数的变化,当循环省略表达式2的判断,就是死循环,一直真
    
    //遍历字符串
    func main() {
    	str := "123ABCabc"
    	for i,value := rang str {
    		fmt.Println(i,value)
    	}
    }
    
    for i:=1;i<=9;i++ {
    	for j:=1;j<=9;j++ {
    		if j<9 {
    			fmt.Print("o ")
    		}else {
    			fmt.Println("o")
    		}
    	}
    }
    
    for i:=1;i<=9;i++ {
    	for j:=1;j<=i;j++ {
    		if j<i {
    			fmt.Print("o ")
    		}else {
    			fmt.Println("o")
    		}
    	}
    }
    
  • break,continue,goto,go语言中有这些控制语句,break跳出当前循环体,continue跳过本次循环,goto跳到指定位置。比如loop: 后面goto loop

生成随机数

Go语言标准库中关于随机函数提供了两种包,分别是“math/rand”和“crypto/rand”
标准库学习指南中文版	https://studygolang.com/pkgdoc

常用方式
const layout = "2006-01-02 15:04:05"
const layout = "2006/01/02 15:04:05"	时间必须写这个是为了纪念go语言诞生	
a := time.Now().Format(layout)
b := time.Now().Unix()
c := rand.Intn(100)
此时a打印出来的当前时间就是按这个格式,layout是个设计模板的意思
b是int64的时间戳
rand.Intn(n)	是一个取值0到n-1的随机整数
比如5-49之间的随机数就是rand.Intn(45)+3
注意当种子数相同时,随机模块前K次取出来的值,与下一次程序运行前K次取出来的值是相同的,
so我们常用时间戳来设置种子数

rand.Seed(time.Now().Unix())
func main() {
	rand.Seed(time.Now().Unix())
	for i := 0; i < 10; i++ {
		g := rand.Intn(100)
		fmt.Println(g)
	}
}

time.sleep()	程序休眠,()当中是纳秒

函数

go语言中函数写法如下,可以有多个返回值,正常参数是a int,b string,如果相同可以简写,同理返回值也是。这里注意当值类型的变量传入函数当参数时,是把变量的值复制一份给函数,并不会修改原来的变量值。引用类型有:切片,map,接口,channel,func,指针

func xxoo(a,b int) (c,d int) {
	c = a + b
	d = a*b
	return c,d
}
  • 当需要不固定的参数时候用…,如func xxoo(a ... int) (c,d int) 这时候a ... 就是0个或者多个int类型参数,a ...是一个切片,注意可变参数必须放在参数最后一个位置
func xxoo(a ... int) int {	//累加
	sub := 0
	for _,arg := range a{
		sub += arg
	}
	return sub
}
  • 函数可以当做参数传给另外一个函数

  • 匿名函数

    m := func(){}	#建立了一个匿名函数赋值给m变量
    m()	#调用
    
  • 闭包
    定义了一个函数,函数内部有嵌套一个匿名函数。这个函数的返回值是一个函数,返回的匿名函数又调用了外层函数的变量

    
    func sayword(name string) func(){
    	return func(){
    		fmt.Printf("%v你好!",name)
    	}
    }
    
    func main(){
    	k := sayword("蔡徐坤")
    	k()
    }
    

内置函数

  1. append
    用法k := append(k,1),加入k是切片,就是在原来切片末尾添加1这个元素
  2. copy
    由于切片是内存指向数据,如果使用普通赋值,会把两个切片都指向同一片内存空间,如果要复制使用copy函数,copy(b,a),将a的元素拷贝给b
  3. make
    由于切片的容量一般没有限制,为了程序的快速运行,一般是在切片定义的时候想好容量大小,后续就不用再继续扩容,通常做法使用make函数,k = make([]int,5,10)定义一个切片k元素是整形,长度是5,容量是10

结构体

结构体是由一系列具有相同类型或不同类型的数据构成的数据集合,是值类型。有点像其他语言中的类,两个结构体进行==比较,要比对里面的所有字段值

定义封装结构体
type Person struct {
	name string
	age int
	hobby []string
}

需要使用的地方就能var p Person 申明一个结构体,然后一步步具体实例p.name p.age等
其他还有以下两种使用方式
var p = Person{		//第一种一步到位
age:18,
name:"xxoo",
}
	
func newPerson(name string,age int,hobby []string) Person{//第二种定义构造
	return Person{
		name:  name,
		age:   age,
		hobby: hobby,
	}
}2种新建一个构造函数newperson(约定俗成使用new打头就是构造函数),在需要的地
方直接调用函数,接收返回值就可以。如果结构体里面内容比较多,通常使用*person
作为返回值类型,而返回值写return &person 这样操作的都是指针,这个较常用

方法是作用于特定类型的函数,不是谁都能调用的,如下,(p person)定义接收者为
person类型,前面的p为实例,约定用结构体的第一个小写字母
func (p Person) wang(){
	fmt.Println("汪汪汪")
}
p.wang()

func (p *People) run () {
	fmt.Printf("%v正在跑步",p.name)
	p.weight--
}
使用指针时是为了更高效,因为指针较小,而且可以指向自己的属性同时修改

匿名属性,把属性名称去掉,不允许两个同类型的匿名属性
type Person struct {
	string
	int
}

封装

go语言当中也是有面向对象编程的,就是我们的结构体。由于封装需要被其他包调用所以常大写开头,而如果结构体中的属性是小写的话,也是不允许外部直接访问的,需要通过特定方法调用私有属性

type People struct {
	name string
	age int
}

定义了公有Setname方法,可以外部直接调用,由于要修改原name属性必须使用指针如下
func (p *People) Setname(newname string) {
	p.name = newname
}

func (p *People) Getname() {
	return p.name
}

继承

类型于其他编程语言的使用方式,还使用匿名属性的特点

type People struct {
	name string
	age int
}

type Student struct {
	classroom string
	People
}

s := Student{classroom:"三年一班",People:People{name:"奇多",age:18}}
fmt.Println(s.name)
这里学生结构体逻辑上,是从属于人这个结构体,这里结构体Student里People使用了匿名
属性的特点,全写是peo People,省略属性名字,就直接People了。调用结果就是"奇多"
同理属于People的方法,s也能直接调用了

接口

接口是一个类型(心里反复念无数遍),它把所有的具有共性的方法定义在一起,只能有名称,参数,返回值。任何其他类型只要实现了这些所有方法就是实现了这个接口,约定俗成在名称后面加er。


type Phoner interface {	//定义了一个接口Phoner
	call()
}

//定义了一个结构体NokiaPhone
type NokiaPhone struct {
	name string
	price float64
}

//定义了一个结构体IPhone
type IPhone struct {}

func (nokiaPhone NokiaPhone) call() {
	fmt.Println("I am Nokia, I can call you!")
}
func (iPhone IPhone) call() {
	fmt.Println("I am iPhone, I can call you!")
}


var phoner Phoner = NokiaPhone{name:"NokiaN7",price:3988.88,}
phoner.call()
当将NokiaPhone赋予变量phoner和当将iPhone赋予变量phoner时,调用相同
的方法,产生不同的结果

或者
func (x Phoner){
	x.call()
}

很明显接口限制了类型实现的方法,当实现方法的是值类型参数时,可以把结构
体或者结构体指针赋给方法变量。当实现方法的是指针类型参数接收者时,只能
传结构体指针给接口变量

接口的嵌套,语法参照结构体,一模一样

空接口

type Xxooer interface{}	//定义空接口
由于空接口,所有类型的数据都可以属于这个接口类型特别是在函数的参数传递

func aabb (a interface{}){
	此时a就可以是任何类型数据传入函数了
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值