Golang学习笔记(一)

目录

1 变量

1.1  声明变量

1.2 初始化 

1.3 匿名变量

2 数据类型

2.1 常用类型

2.2  数据类型转换

3 常量

4 fmt

4.1 输出

4.2 打印格式

4.3 输入

5 流程控制

5.1 IF

5.2 Switch

5.3 FOR

6 函数

6.1 普通函数

6.2 匿名函数

6.3 可变参数

6.4 defer

7 MAP

8 数组和切片

8.1 数组

8.2 切片


1 变量

变量是计算机语言中储存数据的基本单元,变量指定了某存储单元(Memory Location)的名称,该存储单元会存储特定类型的值。

变量又分为局部变量和全局变量。

  • 局部变量,是定义在大括号({})内部的变量,大括号的内部也是局部变量的作用域。
  • 全局变量,是定义在函数和大括号({})外部的变量。

1.1  声明变量

变量声明以关键字var开头,变量类型放在变量的后面,行尾无需分号。

var name   type
var 变量名 变量类型

声明多个变量:

var (
        a string
        b int
        c bool
    )

var (
        name = "golang"
        age = 20
        height int
    )

var width, height int = 100, 50

1.2 初始化 

如果变量有初始值,那么 Go 能够自动推断具有初始值的变量的类型。因此,如果变量有初始值,就可以在变量声明中省略 type

var a int = 10  //标准
var b = 10      //省略 type,自动推断类型
name, age := "golang", 29  //简短声明, := 操作符的左边至少有一个变量是尚未声明的

1.3 匿名变量

在使用多重赋值时,尤其是当Go语言的函数返回多个值,而想要忽略某个值时,那么就可以使用匿名变量,即下画线“_”替换即可,也称作空白符。

 x, _ := foo()
 _, y := foo()

匿名变量既不占用命名空间,也不会分配内存。 

注意:

GOlang的全局变量只声明不使用会报错。

处理方法:关闭golang 的 variable declared but not used 

2 数据类型

在Go语言中,有以下几种数据类型。

基本数据类型(原生数据类型):整型、浮点型、复数型、布尔型、字符串、字符(byte、rune)。

复合数据类型(派生数据类型):数组(array)、切片(slice)、映射(map)、函数(function)、结构体(struct)、通道(channel)、接口(interface)、指针(pointer)。

2.1 常用类型

1)整型

 2)浮点型

 3)字符

byte 是 uint8 的别名。
rune 是 int32 的别名。

 4)字符串

 字符串是字节的集合。双引号书写字符串被称为字符串字面量(string literal),这种字面量不能跨行。Go 中的字符串是兼容 Unicode 编码的,并且使用 UTF-8 进行编码。

s1 := "hello"

多行字符串需要使用反引号“`”,多用于内嵌源码和内嵌数据。

s1 := `第一行
    第二行
    第三行
    `

 转义字符

常用方法

5)复数类型

complex64:实部和虚部都是 float32 类型的的复数。
complex128:实部和虚部都是 float64 类型的的复数。

内建函数complex用于创建一个包含实部和虚部的复数。complex 函数的定义如下:

func complex(r, i FloatType) ComplexType

也可以使用简短语法:
c := 6 + 7i

2.2  数据类型转换

Go 有着非常严格的强类型特征。Go 没有自动类型转换。

必须采用数据类型前置加括号的方式进行强制类型转换。

 3 常量

常量中的数据类型只可以是布尔型、数字型(整型、浮点型和复数型)和字符串。常量的定义格式如下:

const 标识符 [类型] = 值

const a int = 10
a = 20     // 不允许对常量重新赋值
const b = math.Sqrt(4) // 常量的值会在编译的时候确定,所以不允许将函数的返回值赋值给常量

Go语言现阶段没有提供枚举,可以使用常量组模拟枚举。

import "fmt"

const(
    status = 0
    female = 2
)

fun main(){
 fmt.println(status,female)
}

iota

iota,特殊常量值,是一个系统定义的可以被编译器修改的常量值。

iota只能被用在常量的赋值中,在每一个const关键字出现时,被重置为0,然后每出现一个常量,iota所代表的数值会自动增加1。iota可以理解成常量组中常量的计数器。

const (
            n1 = iota //0
            n2        //1
            n3        //2
            n4        //3
        )

4 fmt

4.1 输出

fmt包实现了类似C语言printf和scanf的格式化I/O。主要分为向外输出内容和获取输入内容两大部分。

1) Print

Print系列函数会将内容输出到系统的标准输出,区别在于Print函数直接输出内容,Printf函数支持格式化输出字符串,Println函数会在输出内容的结尾添加一个换行符。

func main() {
    fmt.Print("在终端打印该信息。")
    name := "枯藤"
    fmt.Printf("我是:%s\n", name)
    fmt.Println("在终端打印单独一行显示")
}

2) Fprint

Fprint系列函数会将内容输出到一个io.Writer接口类型的变量w中,我们通常用这个函数往文件中写入内容。 

// 向标准输出写入内容
fmt.Fprintln(os.Stdout, "向标准输出写入内容")
fileObj, err := os.OpenFile("./xx.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
    fmt.Println("打开文件出错,err:", err)
    return
}
name := "枯藤"
// 向打开的文件句柄中写入内容
fmt.Fprintf(fileObj, "往文件中写如信息:%s", name)

3)Sprint

Sprint系列函数会把传入的数据生成并返回一个字符串。

s1 := fmt.Sprint("枯藤")
s2 := fmt.Sprintf("name:%s,age:%d", name, age)
s3 := fmt.Sprintln("枯藤")

4)  Errorf函数根据format参数生成格式化字符串并返回一个包含该字符串的错误。

err := fmt.Errorf("这是一个错误")

 4.2 打印格式

通用打印格式

BOOL打印格式

整型打印格式

浮点型打印格式

字符串和字符数组打印格式

指针

4.3 输入

1) fmt

func Scan(a ...interface{}) (n int, err error)
func Scanf(format string, a ...interface{}) (n int, err error)
func Scanln(a ...interface{}) (n int, err error)

2) bufio.NewReader

func bufioDemo() {
    reader := bufio.NewReader(os.Stdin) // 从标准输入生成读对象
    fmt.Print("请输入内容:")
    text, _ := reader.ReadString('\n') // 读到换行
    text = strings.TrimSpace(text)
    fmt.Printf("%#v\n", text)
}

 5 流程控制

 5.1 IF

if 是条件语句,如果 condition 为真,则执行 { 和 } 之间的代码。 

if condition {  
    //...
}
if condition {  
    //...
} else if condition {
    //...
} else {
    //...
}

if 还有另外一种形式,它包含一个 statement 可选语句部分,该组件在条件判断之前运行。 

if statement; condition {  
    //...
}
 if num := 10; num % 2 == 0 { //checks if number is even
        fmt.Println(num,"is even") 
    }  else {
        fmt.Println(num,"is odd")
    }

 注意:else 语句应该在 if 语句的大括号 } 之后的同一行中。如果不是,编译器会不通过。

5.2 Switch

switch 是一个条件语句,用于将表达式的值与可能匹配的选项列表进行比较,并根据匹配情况执行相应的代码块。

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

定义多个表达式: 

letter := "i"
    switch letter {
    case "a", "e", "i", "o", "u": // 一个选项多个表达式
        fmt.Println("vowel")
    default:
        fmt.Println("not a vowel")
    }

 switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。

switch x.(type){
    case type:
       statement(s)      
    case type:
       statement(s)
    default: /* 可选 */
       statement(s)
}

Fallthrough 语句:

在 Go 中,每执行完一个 case 后,会从 switch 语句中跳出来,不再做后续 case 的判断和执行。使用 fallthrough 语句可以在已经执行完成的 case 之后,把控制权转移到下一个 case 的执行代码中。 

func main() {
	num := 75
    //表达式是可选的,可以被省略
	switch  {
	case num < 50:
		fmt.Printf("%d is lesser than 50\n", num)
		fallthrough
	case num < 100:
		fmt.Printf("%d is lesser than 100\n", num)
		fallthrough
	case num < 200:
		fmt.Printf("%d is lesser than 200", num)
	}
}

 

5.3 FOR

for 是 Go 语言唯一的循环语句。Go 语言中并没有其他语言比如 C 语言中的 while 和 do while 循环。

形式1 :for init; condition; post { }
形式2 :for condition { }
形式3 :for { }

init:初始化部门;
condition: 条件;
post: 控制变量增量或减量。

案例: 

for i := 1; i <= 10; i++ {
        fmt.Printf(" %d",i)
    }

break 语句用于在完成正常执行之前突然终止 for 循环 

for i := 1; i <= 10; i++ {
        if i > 5 {
            break //loop is terminated if i > 5
        }
        fmt.Printf("%d ", i)
    }

continue 语句用来跳出 for 循环中当前循环

for i := 1; i <= 10; i++ {
        if i%2 == 0 {
            continue
        }
        fmt.Printf("%d ", i)
    }

6 函数

6.1 普通函数

函数声明通用语法如下:

func functionname(parametername type) returntype {  
    // 函数体(具体实现的功能)
}

func functionname() {  
    // 注: 表示这个函数不需要输入参数,且没有返回值
}

函数使用示例:

func calculatePrice(price int, num int) int {  
    var totalPrice = price * num // 商品总价 = 商品单价 * 数量
    return totalPrice // 返回总价
}

//如果有连续若干个参数,它们的类型一致,那么我们无须一一罗列,只需在最后一个参数后添加该类型。 
func calculatePrice2(price , num int) int {  
    var totalPrice = price * num // 商品总价 = 商品单价 * 数量
    return totalPrice // 返回总价
}

func main() {  
    price, num := 90, 6 // 定义 price 和 num,默认类型为 int
    totalPrice := calculatePrice(price, num)
    fmt.Println("Total price is", totalPrice) // 打印到控制台上
}

多返回值:
Go 语言支持一个函数可以有多个返回值。我们来写个以矩形的长和宽为输入参数,计算并返回矩形面积和周长的函数 rectProps。

func rectProps(length, width float64)(float64, float64) {  
    var area = length * width
    var perimeter = (length + width) * 2
    return area, perimeter    //同时返回两个值,面积和周长
}

func main() {  
    area, perimeter := rectProps(10.8, 5.6)
    fmt.Printf("Area %f Perimeter %f", area, perimeter) 
}

命名返回值:

//从函数中可以返回一个命名值,函数中的 return 语句没有显式返回任何值。由于 area 和 perimeter 在函数声明中指定为返回值, 因此当遇到 return 语句时, 它们将自动从函数返回。

func rectProps(length, width float64)(area, perimeter float64) {  
    area = length * width
    perimeter = (length + width) * 2
    return 

6.2 匿名函数

匿名函数没有函数名,只有函数体,函数可以作为一种类型被赋值给变量,匿名函数也往往以变量方式被传递。

1)定义匿名函数的时候就可以直接使用(仅使用一次)

func main() {
	res := func(length, width float64)float64{
		return length*width
	}(10.6,20.8)
}

2)可以将匿名函数赋值给变量,再通过该变量来调用匿名函数

func main() {    
    res := func(length, width float64)float64{
        return length*width
    }
    res1 := res(2.4,6.2)
    fmt.Println(res1)
}

3)匿名函数作为返回值

func caculate() func(float64,float64){
	area := func(length,width float64 ){
		println(length*width)
	}
	return area
}

6.3 可变参数

如果函数最后一个参数被记作 ...T ,这时函数可以接受任意个 T 类型参数作为最后一个参数。

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true
        }
    }
    if !found {
        fmt.Println(num, "not found in ", nums)
    }
    fmt.Printf("\n")
}

func main() {
    find(89, 89, 90, 95)
}

6.4 defer

 含有 defer 语句的函数,会在该函数将要返回之前,调用另一个函数。

func finished() {  
    fmt.Println("Finished finding largest")
}

func largest(nums []int) {  
    defer finished()
    fmt.Println("Started finding largest")
    max := nums[0]
    for _, v := range nums {
        if v > max {
            max = v
        }
    }
    fmt.Println("Largest number in", nums, "is", max)
}

func main() {  
    nums := []int{78, 109, 2, 563, 300}
    largest(nums)
}

在 largest() 函数将要返回之前,会调用 finished() 函数。 

defer也可以用来延迟方法:

func printA(a int) {  
    fmt.Println("value of a in deferred function", a)
}
func main() {  
    a := 5
    defer printA(a)
    a = 10
    fmt.Println("value of a before deferred function call", a)

}

当一个函数内多次调用 defer 时,Go 会把 defer 调用放入到一个栈中,随后按照后进先出(Last In First Out, LIFO)的顺序执行。

7 MAP

Go 语言提供了内置类型 map,它将值(value)与键(key)关联起来,可以使用相应的键检索值。

1)创建MAP

var 变量名 map[KeyType]ValueType  //使用var关键字定义map

变量名 := make(map[string]int)    //通过向 make 函数传入键和值的类型

var person map[string]int
    if person == nil {
        fmt.Println("map is nil. Going to make one.")
        person = make(map[string]int)
    }

2)添加元素

var country = map[string]string{
		"China":  "Beijing",
		"Italy":  "Rome",
}
country["Japan"] = "XRIBen"

3)检索map值

value, ok := map[key]

func main() {
   var country = map[string]string{
		"China":  "Beijing",
		"Italy":  "Rome",
    }
    country["Japan"] = "XRIBen"
    newCon := "Italy"
    value, ok := country[newCon]
    if ok == true {
        fmt.Println("Capatoal of", newCon, "is", value)
    } else {
        fmt.Println(newCon,"not found")
    }
}

 for range循环遍历

(1)、key 、value都遍历
	for k, v := range countryMap {
		fmt.Println("国家", k, "首都", v)
	}
(2)、只展示value
	for _, v := range countryMap {
		fmt.Println("国家",  "首都", v)
	}
(3)、只展示key
	for k := range countryMap {
		fmt.Println("国家",  k , "首都", countryMap[k])
	}

4)删除元素

删除 map 中 key 的语法是 delete(map, key)。这个函数没有返回值。

delete(country, "Japan")

5)其他

len(personSalary) 函数获取map 的长度。

map 是引用类型。当 map 被赋值为一个新变量的时候,它们指向同一个内部数据结构。因此,改变其中一个变量,就会影响到另一变量。

map 之间不能使用 == 操作符判断,== 只能用来检查 map 是否为 nil。

8 数组和切片

8.1 数组

数组是同一类型元素的集合。一个数组的表示形式为 [n]T。n 表示数组中元素的数量,T 代表每个元素的类型。元素的数量 n 也是该类型的一部分。

1)声明数组

var a [3]int     //int array with length 3
a[0] = 12        // array index starts at 0
a := [3]int{12, 78, 50}  // short hand declaration to create array
a := [...]int{12, 78, 50} // ... makes the compiler determine the length

Go 中的数组是值类型而不是引用类型。这意味着当数组赋值给一个新的变量时,该变量会得到一个原始数组的一个副本。如果对新变量进行更改,则不会影响原始数组。

2)遍历数组

a := [...]float64{67.7, 89.8, 21, 78}
for i := 0; i < len(a); i++ { 
    fmt.Printf("%d   is %.2f\n", i, a[i])
}

for i, v := range a {
    fmt.Printf("%d   is %.2f\n", i, v)
}

3)多维数组

func printarray(a [3][2]string) {
    for _, v1 := range a {
        for _, v2 := range v1 {
            fmt.Printf("%s ", v2)
        }
        fmt.Printf("\n")
    }
}

func main() {
    a := [3][2]string{
        {"lion", "tiger"},
        {"cat", "dog"},
        {"pigeon", "peacock"}, 
    }
    printarray(a)
}

8.2 切片

1)声明

切片由 []T 表示,没有元素数量。

a := [5]int{76, 77, 78, 79, 80}
var b []int = a[1:4] // creates a slice from a[1] to a[3]

    var b []int = arr[start:end] 
    var b []int = arr[:end]        
    var b []int = arr[start:]        
    var b []int = arr[:] 
    var b = arr[:len(arr)-1]      //去掉切片的最后一个元素


c := []int{6, 7, 8} // creates and array and returns a slice reference

 2)修改切片

切片自己不拥有任何数据。它只是底层数组的一种表示。对切片所做的任何修改都会反映在底层数组中。

func main() {
    darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
    dslice := darr[2:5]
    fmt.Println("array before", darr)
    for i := range dslice {
        dslice[i]++
    }
    fmt.Println("array after", darr)
}

 3)make创建切片

func make([]T,len,cap)[]T  函数通过传递类型,长度和容量来创建切片。容量是可选参数, 默认值为切片长度。make 函数创建一个数组,并返回引用该数组的切片。

i := make([]int, 5, 5)

4)其他

切片可以通过len()方法获取长度,可以通过cap()方法获取容量。

函数append()用于往切片中追加新元素,可以向切片里面追加一个或者多个元素,也可以追加一个切片。

函数copy()会复制切片元素,将源切片中的元素复制到目标切片中,返回复制的元素的个数。 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值