Golang基础


title: Golang
top: 31
date: 2020-11-13 16:55:31
tags:

  • Golang基础
    categories: Golang

变量声明

goLang中用 var 声明变量,goLang中声明的变量必须得使用,否则编译不会通过

var name string
var age int
var flag bool
// 多个变量声明
var (
    var name string
	var age int
	var flag bool
)
// 声明变量并赋值
var name string = "张三"

常量与iota

const pi = 3.14
const e = 2.718
const(
    const pi = 3.14
    const e = 2.718
)

const同时声明多个常量时,如果省略了值,则表示和上面一行的值相同

const(
	n1 = 100
    n2
    n3
)
// n1,n2,n3的值都是100

iota

iotagoLang的常量计数器,只能在常量表达式中使用。

iotaconst关键字出现是将被重置为0。const中每新增一行常量声明将使 iota 计数一次iota可理解为const语句块中的行索引

package main

import (
	"fmt"
)

const (
	n1 = iota
	n2
	n3
)

func main() {
	fmt.Println(n1)
	fmt.Println(n2)
	fmt.Println(n3)

}
// print 0 ; 1 ; 2
// example 2
const (
	n1 = iota
	n2
	_
	n3
)
// _(短下划线表匿名变量)
// print 0 ; 1 ; 3
// example 3
const (
	n1 = iota
	n2 = 100
	n3
    n4 = iota
)
// print 0 ; 100 ; 100 ; 3
// example 4 多个iota定义在一行
const(
	n1,n2 = iota+1, iota+2  // 1,2
    n3,n4   // 2,3
    n5,n6   // 3,4
)

定义数量级

const(
	_ = iota
    KB = 1<<(10*iota) // 1左移10位 1024
    MB = 1<<(10*iota) // 1024 再左移10位
    GB = 1<<(10*iota)
    TB = 1<<(10*iota)
    PB = 1<<(10*iota)
)

流程控制

if else(分支结构)

if 表达式1 {
    分支1
} else if 表达式2 {
    分支2
} else{
    分支3
}

// example
func ifDemo1() {
	if score := 65;score >= 90 {
		fmt.Println("A")
	} else if score > 75 {
		fmt.Println("B")
	} else {
		fmt.Println("C")
	}
}

for(循环结构)

for 初始语句;条件表达式;结束语句{
    循环体语句
}
func forDemo() {
	for i := 0; i < 10; i++ {
		fmt.Println(i)
	}
}

func forDemo2() {
	i := 0
	for ; i < 10; i++ {    //省略初始
		fmt.Println(i)
	}
}

func forDemo3() {
	i := 0
	for i < 10 {     // 省略初始与结束
		fmt.Println(i)
		i++
	}
}

for循环可以通过breakgotoreturnpanic语句强制退出循环

for range 键值循环

// 1 遍历数组/切片
for key, value := range []int{1, 2, 3, 4} {
    fmt.Printf("key:%d  value:%d\n", key, value)
}

// 2 遍历字符串
var str = "hello 你好"
for key, value := range str {
    fmt.Printf("key:%d value:0x%x\n", key, value)
}

// 3 遍历map
m := map[string]int{
    "hello": 100,
    "world": 200,
}
for key, value := range m {
    fmt.Println(key, value)
}

// 4 c := make(chan int)
go func() {
    c <- 1
    c <- 2
    c <- 3
    close(c)
}()
for v := range c {
    fmt.Println(v)
}

switch case

func switchDemo1() {
	finger := 3
	switch finger {
	case 1:
		fmt.Println("大拇指")
	case 2:
		fmt.Println("食指")
	case 3:
		fmt.Println("中指")
	case 4:
		fmt.Println("无名指")
	case 5:
		fmt.Println("小拇指")
	default:
		fmt.Println("无效的输入!")
	}
}

// 一个分支可以有多个值,多个case值中间使用英文逗号分隔。
func testSwitch3() {
	switch n := 7; n {
	case 1, 3, 5, 7, 9:
		fmt.Println("奇数")
	case 2, 4, 6, 8:
		fmt.Println("偶数")
	default:
		fmt.Println(n)
	}
}

// 分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量。
func switchDemo4() {
	age := 30
	switch {
	case age < 25:
		fmt.Println("好好学习吧")
	case age > 25 && age < 35:
		fmt.Println("好好工作吧")
	case age > 60:
		fmt.Println("好好享受吧")
	default:
		fmt.Println("活着真好")
	}
}

fallthrough语法可以执行满足条件case下一个case

func switchDemo5() {
	s := "a"
	switch {
	case s == "a":
		fmt.Println("a")
		fallthrough
	case s == "b":
		fmt.Println("b")
	case s == "c":
		fmt.Println("c")
	default:
		fmt.Println("...")
	}
}
/*output 
	a
	b
*/ 

goto(跳转到指定标签)

goto语句通过标签进行代码间的无条件跳转。goto语句可以在快速跳出循环、避免重复退出上有一定的帮助。

func gotoDemo2() {
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if j == 2 {
				// 设置退出标签
				goto breakTag
			}
			fmt.Printf("%v-%v\n", i, j)
		}
	}
	return
	// 标签
breakTag:
	fmt.Println("结束for循环")
}

数组

数组的长度是数组类型的一部分

// 定义一个长度为3元素类型为int的数组a
// var 数组变量名 [元素数量]T
var a [3]int

数组的初始化

func main() {
	var testArray [3]int    //数组会初始化为int类型的0值
	var numArray = [3]int{1, 2}     //使用指定的初始值完成初始化
	var cityArray = [3]string{"北京", "上海", "深圳"} //使用指定的初始值完成初始化
    
	fmt.Println(testArray)                      //[0 0 0]
	fmt.Println(numArray)                       //[1 2 0]
	fmt.Println(cityArray)                      //[北京 上海 深圳]
}
// 根据初始值的个数自行推断数组的长度
func main() {
	var testArray [3]int
	var numArray = [...]int{1, 2}
	var cityArray = [...]string{"北京", "上海", "深圳"}
    
	fmt.Println(testArray)                          //[0 0 0]
	fmt.Println(numArray)                           //[1 2]
	fmt.Printf("type of numArray:%T\n", numArray)   //type of numArray:[2]int
	fmt.Println(cityArray)                          //[北京 上海 深圳]
	fmt.Printf("type of cityArray:%T\n", cityArray) //type of cityArray:[3]string
}
// 指定索引值的方式来初始化数组
func main() {
	a := [...]int{1: 1, 3: 5}
	fmt.Println(a)                  // [0 1 0 5]
	fmt.Printf("type of a:%T\n", a) //type of a:[4]int
}

数组的遍历

func main() {
	var a = [...]string{"北京", "上海", "深圳"}
	// 方法1:for循环遍历
	for i := 0; i < len(a); i++ {
		fmt.Println(a[i])
	}

	// 方法2:for range遍历
	for index, value := range a {
		fmt.Println(index, value)
	}
}

多维数组

二维数组的定义

func main() {
	a := [3][2]string{
		{"北京", "上海"},
		{"广州", "深圳"},
		{"成都", "重庆"},
	}
	fmt.Println(a) //[[北京 上海] [广州 深圳] [成都 重庆]]
	fmt.Println(a[2][1]) //支持索引取值:重庆
}

多维数组只有第一层可以使用...来让编译器推导数组长度

//支持的写法
a := [...][2]string{
	{"北京", "上海"},
	{"广州", "深圳"},
	{"成都", "重庆"},
}
// 不支持 多维数组的内层使用...
b := [3][...]string{
	{"北京", "上海"},
	{"广州", "深圳"},
	{"成都", "重庆"},
}

二维数组的遍历

func main() {
	a := [3][2]string{
		{"北京", "上海"},
		{"广州", "深圳"},
		{"成都", "重庆"},
	}
	for _, v1 := range a {
		for _, v2 := range v1 {
			fmt.Printf("%s\t", v2)
		}
		fmt.Println()
	}
}

切片

// 切片类型声明
var 变量名 []类型
func main() {
	// 声明切片类型
	var a []string              //声明一个字符串切片
	var b = []int{}             //声明一个整型切片并初始化
	var c = []bool{false, true} //声明一个布尔切片并初始化
	var d = []bool{false, true} //声明一个布尔切片并初始化
	fmt.Println(a)              //[]
	fmt.Println(b)              //[]
	fmt.Println(c)              //[false true]
	fmt.Println(a == nil)       //true
	fmt.Println(b == nil)       //false
	fmt.Println(c == nil)       //false
	// fmt.Println(c == d)   //切片是引用类型,不支持直接比较,只能和nil比较
}

切片拥有自己的长度和容量,我们可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量

切片表达式

a[low : high : max]

切片表达式中的lowhigh表示一个索引范围(左包含,右不包含),容量为max-low

func main() {
	a := [5]int{1, 2, 3, 4, 5}
	t := a[1:3:5]
	fmt.Printf("t:%v len(t):%v cap(t):%v\n", t, len(t), cap(t))
}
//  output  t:[2 3] len(t):2 cap(t):4

使用make()函数构造切片

make([]T, size, cap)
/*
T:切片的元素类型
size:切片中元素的数量
cap:切片的容量
*/
func main() {
	a := make([]int, 2, 10)
	fmt.Println(a)      //[0 0]
	fmt.Println(len(a)) //2
	fmt.Println(cap(a)) //10
}

判断切片是否为空

要检查切片是否为空,请始终使用len(s) == 0来判断,而不应该使用s == nil来判断。

切片的赋值拷贝

func main() {
	s1 := make([]int, 3) //[0 0 0]
	s2 := s1             //将s1直接赋值给s2,s1和s2共用一个底层数组
	s2[0] = 100
	fmt.Println(s1) //[100 0 0]
	fmt.Println(s2) //[100 0 0]
}

append()方法为切片添加元素

func main(){
	var s []int
	s = append(s, 1)        // [1]
	s = append(s, 2, 3, 4)  // [1 2 3 4]
	s2 := []int{5, 6, 7}  
	s = append(s, s2...)    // [1 2 3 4 5 6 7]  ...表示拆开
}
var citySlice []string
// 追加一个元素
citySlice = append(citySlice, "北京")
// 追加多个元素
citySlice = append(citySlice, "上海", "广州", "深圳")
// 追加切片
a := []string{"成都", "重庆"}
citySlice = append(citySlice, a...)
fmt.Println(citySlice) //[北京 上海 广州 深圳 成都 重庆]

从切片中删除元素

Go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。

func main() {
	// 从切片中删除元素
	a := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// 要删除索引为2的元素
	a = append(a[:2], a[3:]...)
	fmt.Println(a) //[30 31 33 34 35 36 37]
}

使用copy()函数复制切片

由于切片是引用类型,所以a和b其实都指向了同一块内存地址。修改b的同时a的值也会发生变化。

Go语言内建的copy()函数可以迅速地将一个切片的数据复制到另外一个切片空间中,类似于python中的深复制。

func main() {
	// copy()复制切片
	a := []int{1, 2, 3, 4, 5}
	c := make([]int, 5, 5)
	copy(c, a)     //使用copy()函数将切片a中的元素复制到切片c
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1 2 3 4 5]
	c[0] = 1000
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1000 2 3 4 5]
}

Go语言中的指针

取变量指针的语法如下:

ptr := &v    // v的类型为T
/*
    v:代表被取地址的变量,类型为T
    ptr:用于接收地址的变量,ptr的类型就为*T,称做T的指针类型。*代表指针。
*/
func main() {
	a := 10
	b := &a
	fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
	fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
	fmt.Println(&b)                    // 0xc00000e018
}

指针取值

func main() {
	//指针取值
	a := 10
	b := &a // 取变量a的地址,将指针保存到b中
	fmt.Printf("type of b:%T\n", b)
	c := *b // 指针取值(根据指针去内存取值)
	fmt.Printf("type of c:%T\n", c)
	fmt.Printf("value of c:%v\n", c)
}

总结: 取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。

new()与make()

var a1 *int   // 未赋值的初始化时,指向空指针
var a2 = new(int)  // 创建指针
fmt.println(a1) // <nil>
fmt.println(a2) // 0xc000540a8

make也是用于内存分配的,区别于new,它只用于slice、map、chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型。

func main() {
	var b map[string]int
	b = make(map[string]int, 10)
	b["沙河娜扎"] = 100
	fmt.Println(b)
}

new与make的区别

  1. 二者都是用来做内存分配的。
  2. make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
  3. 而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。

map

Go语言中提供的映射关系容器为map,其内部使用散列表(hash)实现。

map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。用make()初始化。

//定义语法如下
map[KeyType]ValueType
/*
    KeyType:表示键的类型
    ValueType:表示键对应的值的类型
*/
make(map[KeyType]ValueType, [cap])   //cap表示map的容量

map基本使用

func main() {
	scoreMap := make(map[string]int, 8)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	fmt.Println(scoreMap)
	fmt.Println(scoreMap["小明"])
	fmt.Printf("type of a:%T\n", scoreMap)
}
/*  output
    map[小明:100 张三:90]
    100
    type of a:map[string]int
*/
func main() {
	userInfo := map[string]string{
		"username": "沙河小王子",
		"password": "123456",
	}
	fmt.Println(userInfo) //
}

判断某个键是否存在

value, ok := map[key]
func main() {
	scoreMap := make(map[string]int)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	// 如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值
	v, ok := scoreMap["张三"]
	if ok {
		fmt.Println(v)
	} else {
		fmt.Println("查无此人")
	}
}

map的遍历

func main() {
	scoreMap := make(map[string]int)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	scoreMap["娜扎"] = 60
	for k, v := range scoreMap {
		fmt.Println(k, v)
	}
}

delete()函数删除键值对

delete(map, key)
func main(){
	scoreMap := make(map[string]int)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	scoreMap["娜扎"] = 60
	delete(scoreMap, "小明")//将小明:100从map中删除
	for k,v := range scoreMap{
		fmt.Println(k, v)
	}
}

按指定顺序遍历map

func main() {
	rand.Seed(time.Now().UnixNano()) //初始化随机数种子

	var scoreMap = make(map[string]int, 200)

	for i := 0; i < 100; i++ {
		key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
		value := rand.Intn(100)          //生成0~99的随机整数
		scoreMap[key] = value
	}
	//取出map中的所有key存入切片keys
	var keys = make([]string, 0, 200)
	for key := range scoreMap {
		keys = append(keys, key)
	}
	//对切片进行排序
	sort.Strings(keys)
	//按照排序后的key遍历map
	for _, key := range keys {
		fmt.Println(key, scoreMap[key])
	}
}

函数

函数定义

func 函数名(参数)(返回值){
    函数体
}
  • 函数名:由字母、数字、下划线组成。但函数名的第一个字母不能是数字。在同一个包内,函数名也称不能重名(包的概念详见后文)。
  • 参数:参数由参数变量和参数变量的类型组成,多个参数之间使用,分隔。
  • 返回值:返回值由返回值变量和其变量类型组成,也可以只写返回值的类型,多个返回值必须用()包裹,并用,分隔。
  • 函数体:实现指定功能的代码块。
func intSum(x int, y int) int {
	return x + y
}

// 参数的类型简写。多个连续的参数类型一致时,可以只在最后统一声明。
func intSum(x, y int) int {
	return x, y
}

// 可变长参数,y可以传入n(n>=0)个数,相当于切片
func intSum(x, y ...int) int {
	return x, y
}
/*
返回值可以命名也可以不命名;
命名的返回值相当于在函数中声明一个变量
*/ 
func intSum(x int, y int) (ret int) {
	ret = x + y
	return   // 使用命名的返回值return后可以省略
}

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值