GO语言基础(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yujuan110/article/details/82859755

1变量

1.1变量声明

var v1 int
var v2 string
var v3 [10]int // 数组
var v4 []int // 数组切片
var v5 struct { 
 f int
} 
var v6 *int // 指针
var v7 map[string]int // map,key为string类型,value为int类型
var v8 func(a int) int

同时声明多个变量

    var ( 
     v1 int
     v2 string
    ) 

1.2变量初始化

对变量初始化时,var可用可不用

var v1 int = 10 // 正确的使用方式1 
var v2 = 10 // 正确的使用方式2,编译器可以自动推导出v2的类型
v3 := 10 // 正确的使用方式3,编译器可以自动推导出v3的类型

注意:=和:=的区别 ,:=用于初始化变量

1.3变量赋值

变量赋值和变量初始化不一样

var v10 int
v10 = 123 

go语言支持多重赋值

 i, j = j, i 

1.4匿名变量

func GetName() (firstName, lastName, nickName string) { 
 return "May", "Chan", "Chibi Maruko" 
} 
//若只想获得nickName,则函数调用语句可以用如下方式编写:
_, _, nickName := GetName() 

1.5常量

const Pi float64 = 3.14159265358979323846 
const zero = 0.0 // 无类型浮点常量
const (
 size int64 = 1024 
 eof = -1 // 无类型整型常量
) 
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重赋值
const a, b, c = 3, 4, "foo" 
// a = 3, b = 4, c = "foo", 无类型整型和字符串常量

常量定义的右值也可以是一个在编译期运算的常量表达式,比如
const mask = 1 << 3
由于常量的赋值是一个编译期行为,所以右值不能出现任何需要运行期才能得出结果的表达
,比如试图以如下方式定义常量就会导致编译错误:
const Home = os.GetEnv(“HOME”)

1.3预定义常量

Go语言中的预定义常量:true,false,iota

iota是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其值增1。

const ( // iota被重设为0
 c0 = iota // c0 == 0 
 c1 = iota // c1 == 1 
 c2 = iota // c2 == 2 
) 
const ( 
 a = 1 << iota // a == 1 (iota在每个const开头被重设为0) 
 b = 1 << iota // b == 2 
 c = 1 << iota // c == 4 
) 

如果两个const的赋值语句的表达式是一样的,那么可以省略后一个赋值表达式。因此,上面的前两个const语句可简写为:

const ( // iota被重设为0
 c0 = iota    // c0 == 0 
 c1              // c1 == 1 
 c2              // c2 == 2 
) 
const ( 
 a = 1 <<iota        // a == 1 (iota在每个const开头被重设为0) 
 b                 // b == 2 
 c                 // c == 4 
) 

1.4枚举

Go语言没有像其他编程语言一样的enum关键字

const ( 
 Sunday = iota
 Monday 
 Tuesday 
 Wednesday 
 Thursday 
 Friday 
 Saturday 
 numberOfDays // 这个常量没有导出 
) 

同Go语言的其他符号(symbol)一样,以大写字母开头的常量在包外可见。
以上例子中numberOfDays为包内私有,其他符号则可被其他包访问。

2类型

Go语言内置以下这些基础类型:

 布尔类型:bool。
 整型:int8、byte、int16、int、uint、uintptr等。
 浮点类型:float32、float64。
 复数类型:complex64、complex128。
 字符串:string。
 字符类型:rune。
 错误类型:error。
此外,Go语言也支持以下这些复合类型:
 指针(pointer)
 数组(array)
 切片(slice)
 字典(map)
 通道(chan)
 结构体(struct)
 接口(interface)

2.1布尔类型

var v1 bool
v1 = true
v2 := (1 == 2) // v2也会被推导为bool类型

布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换

b = 1 // 编译错误
b = bool(1) // 编译错误
以下的用法才是正确的:
var b bool
b = (1!=0) // 编译正确 
fmt.Println("Result:", b) // 打印结果为Result: true 

2.2整型

在这里插入图片描述

int和int32是不同类型,编译器不是帮助做自动转换

var value2 int32
value1 := 64 // value1将会被自动推导为int类型
value2 = value1 // 编译错误
编译错误类似于:
cannot use value1 (type int) as type int32 in assignment。
使用强制类型转换可以解决这个编译错误:
value2 = int32(value1) // 编译通过
//开发者在做强制类型转换时,需要注意数据长度被截短而发生的数据精
度损失(比如将浮点数强制转为整数)和值溢出(值超过转换的目标类型的值范围时)问题。

//两个不同类型的整型数不能直接比较,比如int8类型的数和int类型的数不能直接比较,但
各种类型的整型变量都可以直接与字面常量(literal)进行比较

2.3位运算

在这里插入图片描述

2.4浮点类型

float32和float64的关系与前面的整型一样
浮点数作比较

import "math" 
// p为用户自定义的比较精度,比如0.00001 
func IsEqual(f1, f2, p float64) bool { 
 return math.Fdim(f1, f2) < p 
} 

2.5复数

1. 复数表示

复数表示的示例如下:

var value1 complex64 // 由2个float32构成的复数类型
value1 = 3.2 + 12i 
value2 := 3.2 + 12i // value2是complex128类型
value3 := complex(3.2, 12) // value3结果同 value2 

2.实部和虚部

对于一个复数z = complex(x, y),就可以通过Go语言内置函数real(z)获得该复数的实部,也就是x,通过imag(z)获得该复数的虚部,也就是y。

2.6 字符串

var str string // 声明一个字符串变量
str = "Hello world" // 字符串赋值
ch := str[0] // 取字符串的第一个字符
fmt.Printf("The length of \"%s\" is %d \n", str, len(str)) 
fmt.Printf("The first character of \"%s\" is %c.\n", str, ch) 

2.7 数组

常规的数组声明方法:

[32]byte // 长度为32的数组,每个元素为一个字节
[2*N] struct { x, y int32 } // 复杂类型数组
[1000]*float64 // 指针数组
[3][5]int // 二维数组
[2][2][2]float64 // 等同于[2]([2]([2]float64))

1. 元素访问

可以使用数组下标来访问数组中的元素。与C语言相同,数组下标从0开始,len(array)-1则表示最后一个元素的下标。下面的示例遍历整型数组并逐个打印元素内容:

for i := 0; i < len(array); i++ { 
 fmt.Println("Element", i, "of array is", array[i]) 
} 

Go语言还提供了一个关键字range,用于便捷地遍历容器中的元素。当然,数组也是range的支持范围。上面的遍历过程可以简化为如下的写法:

for i, v := range array { 
 fmt.Println("Array element[", i, "]=", v) 
} 

2. 值类型

在Go语言中数组是一个值类型(value type)。所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。如果将数组作为函数的参数类型,则在函数调用时该参数将发生数据复制。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所传入数组的一个副本

2.8数组切片

数组切片就像一个指向数组的指针,实际上它拥有自己的数据结构,而不仅仅是
个指针。数组切片的数据结构可以抽象为以下3个变量:

  • 一个指向原生数组的指针;
  • 数组切片中的元素个数;
  • 数组切片已分配的存储空间

从底层实现的角度来看,数组切片实际上仍然使用数组来管理元素,因此它们之间的关系让C++程序员们很容易联想起STL中std::vector和数组的关系。基于数组,数组切片添加了一系列管理功能,可以随时动态扩充存放空间,并且可以被随意传递而不会导致所管理的元素被重复复制。

1. 创建数组切片

  • 基于数组

    package main
    import “fmt”
    func main() {
    // 先定义一个数组
    var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    // 基于数组创建一个数组切片
    var mySlice []int = myArray[:5]

    }

  • 直接创建

并非一定要事先准备一个数组才能创建数组切片。Go语言提供的内置函数make()可以用于灵活地创建数组切片。下面的例子示范了直接创建数组切片的各种方法。创建一个初始元素个数为5的数组切片,元素初始值为0:
mySlice1 := make([]int, 5)
创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间:
mySlice2 := make([]int, 5, 10)
直接创建并初始化包含5个元素的数组切片:
mySlice3 := []int{1, 2, 3, 4, 5}

2.元素遍历

传统的元素遍历方法如下:

for i := 0; i <len(mySlice); i++ { 
 fmt.Println("mySlice[", i, "] =", mySlice[i]) 
} 

使用range关键字可以让遍历代码显得更整洁。range表达式有两个返回值,第一个是索引,
第二个是元素的值:

for i, v := range mySlice { 
 fmt.Println("mySlice[", i, "] =", v) 
} 

3动态增减元素

  • 与数组相比,数组切片多了一个存储能 力(capacity)的概念,即元素个数和分配的空间可以是两个不同的值。
  • 当前创建的数组切片最多可能需要存储的元素个数为50,那么如果你设置的存储能力小于50,比如20,那么在元素超过20时,底层将会发生至少一次这样的动作——重新分配一块“够大”的内存,并且需要把内容从原来的内存块复制到新分配的内存块,这会产生比较明显的开销。
    *给“够大”这两个字加上引号的原因是系统并不知道多大才是够大,所以只是一个简单的猜测。比如,将原有的内存空间扩大两倍,但两倍并不一定够,所以之前提到的内存重新分配和内容复制的过程很有可能发生多次,从而明显降低系统的整体性能。

如果需要往上例中mySlice已包含的5个元素后面继续新增元素,可以使用append()函数。
下面的代码可以从尾端给mySlice加上3个元素,从而生成一个新的数组切片:

mySlice = append(mySlice, 1, 2, 3) 

函数append()的第二个参数其实是一个不定参数,我们可以按自己需求添加若干个元素,
甚至直接将一个数组切片追加到另一个数组切片的末尾:
mySlice2 := []int{8, 9, 10}
// 给mySlice后面添加另一个数组切片

mySlice2 := []int{8, 9, 10} 
// 给mySlice后面添加另一个数组切片
mySlice = append(mySlice, mySlice2...) 

第二个参数mySlice2后面加了三个点,即一个省略号,如果没有这个省略号的话,会有编译错误,因为按append()的语义,从第二个参数起的所有参数都是待附加的元素。因为mySlice中的元素类型为int,所以直接传递mySlice2是行不通的。加上省略号相
当于把mySlice2包含的所有元素打散后传入。

相当于:
mySlice = append(mySlice, 8, 9, 10)

4. 基于数组切片创建数组切片

oldSlice := []int{1, 2, 3, 4, 5} 
newSlice := oldSlice[:3] // 基于oldSlice的前3个元素构建新数组切片

选择的oldSlicef元素范围甚至可以超过所包含的元素个数,比如newSlice可以基于oldSlice的前6个元素创建,虽然oldSlice只包含5个元素。只要这个选择的范围不超过oldSlice存储能力(即cap()返回的值),那么这个创建程序就是合法的。newSlice中超出oldSlice元素的部分都会填上0。

5.内容复制

slice1 := []int{1, 2, 3, 4, 5} 
slice2 := []int{5, 4, 3} 
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置

2.9 MAP

package main
import "fmt"

type Person struct{
    id string
    name string
    age int 
}

    func main(){
        var personMap map[string] Person
        personMap=make(map[string] Person)
        //插入数据
        personMap["01"]=Person{"01","yujuan",18}
        personMap["02"]=Person{"02","hong",22}
        personMap["03"]=Person{"03","muxi",34}
    
        //查询数据
        person,ok:=personMap["02"]
            
        if ok{ 
            fmt.Println("the person 02 is",person.name," and age is ",person.age)
        }else{
            fmt.Println("there is no person with id 02")
        }   
    
        //删除数据
        delete(personMap,"02")
    }

猜你喜欢

转载自blog.csdn.net/yujuan110/article/details/82859755