Go语言学习之路(二)

一、Go语言运算符

Go 语言内置的运算符有:

  • 算术运算符(+、-、*、/、%、++、--)
  • 关系运算符(==、!=、> 、< 、>= 、<=)
  • 逻辑运算符(&&、||、!)
  • 位运算符

  • 赋值运算符

  • 其他运算符

指针变量 * 和地址值 & 的区别:指针变量保存的是一个地址值,会分配独立的内存来存储一个整型数字。当变量前面有 * 标识时,才等同于 & 的用法,否则会直接输出一个整型数字。

func main() {
   var a int = 4
   var ptr *int
   ptr = &a
   println("a的值为", a);    // 4
   println("*ptr为", *ptr);  // 4
   println("ptr为", ptr);    // 824633794744
}

二、Go语言条件语句和循环语句

2.1 条件语句

 注意:1.Go没有三目运算符,所以不支持?:形式的条件判断。

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

if statement; condition {  
}

例子:

package main

import (  
    "fmt"
)

func main() {  
    if num := 10; num % 2 == 0 { // 判断数字是否为偶数
        fmt.Println(num,"偶数") 
    }  else {
        fmt.Println(num,"奇数")
    }
}

2.2 循环语句

循环语句也是for循环和循环嵌套,而Go支持break、continue、goto。

扫描二维码关注公众号,回复: 15529427 查看本文章

注意:

Go 语言的 goto 语句可以无条件地转移到过程中指定的行。

goto 语句通常与条件语句配合使用。可用来实现条件转移, 构成循环,跳出循环体等功能。

但是,在结构化程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难。

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 10

   /* 循环 */
   LOOP: for a < 20 {
      if a == 15 {
         /* 跳过迭代 */
         a = a + 1
         goto LOOP
      }
      fmt.Printf("a的值为 : %d\n", a)
      a++    
   }  
}

/*
a的值为 : 10
a的值为 : 11
a的值为 : 12
a的值为 : 13
a的值为 : 14
a的值为 : 16
a的值为 : 17
a的值为 : 18
a的值为 : 19
*/

1.Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。

和 C 语言的 for 一样:

for init; condition; post { }

和 C 的 while 一样:

for condition { }

和 C 的 for(;;) 一样:

for { }

init: 一般为赋值表达式,给控制变量赋初值;
condition: 关系表达式或逻辑表达式,循环控制条件;
post: 一般为赋值表达式,给控制变量增量或减量。

2.for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

for key, value := range oldMap {
    newMap[key] = value
}
//以上代码中的 key 和 value 是可以省略。

//如果只想读取 key,格式如下:
for key := range oldMap

//或者这样:
for key, _ := range oldMap

//如果只想读取 value,格式如下:
for _, value := range oldMap

例子1:For-each range 循环,这种格式的循环可以对字符串、数组、切片等进行迭代输出元素。

package main
import "fmt"

func main() {
   strings := []string{"google", "runoob"}
   for i, s := range strings {
      fmt.Println(i, s)
   }


   numbers := [6]int{1, 2, 3, 5}
   for i,x:= range numbers {
      fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
   }  
}

/*
0 google
1 runoob


第 0 位 x 的值 = 1
第 1 位 x 的值 = 2
第 2 位 x 的值 = 3
第 3 位 x 的值 = 5
第 4 位 x 的值 = 0
第 5 位 x 的值 = 0
*/

例子2:for 循环的 range 格式可以省略 key 和 value,如下实例:

package main
import "fmt"

func main() {
    map1 := make(map[int]float32)
    map1[1] = 1.0
    map1[2] = 2.0
    map1[3] = 3.0
    map1[4] = 4.0
   
    // 读取 key 和 value
    for key, value := range map1 {
      fmt.Printf("key is: %d - value is: %f\n", key, value)
    }

    // 读取 key
    for key := range map1 {
      fmt.Printf("key is: %d\n", key)
    }

    // 读取 value
    for _, value := range map1 {
      fmt.Printf("value is: %f\n", value)
    }
}

/*
key is: 1 - value is: 1.000000
key is: 2 - value is: 2.000000
key is: 3 - value is: 3.000000
key is: 4 - value is: 4.000000

key is: 1
key is: 2
key is: 3
key is: 4

value is: 1.000000
value is: 2.000000
value is: 3.000000
value is: 4.000000
*/

三、Go语言函数

3.1 函数定义

Go 语言函数定义格式如下:

func function_name( [parameter list] ) [return_types] {
   函数体
}

函数定义解析:

  • func:函数由 func 开始声明
  • function_name:函数名称,参数列表和返回值类型构成了函数签名。
  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的
  • 函数体:函数定义的代码集合。

例子:

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
   /* 声明局部变量 */
   var result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result
}

/* Go 函数可以返回多个值 */
package main

import "fmt"

func swap(x, y string) (string, string) {
   return y, x
}

func main() {
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)
}
// Runoob Google

3.2 函数参数

函数如果使用参数,该变量可称为函数的形参。

形参就像定义在函数体内的局部变量。

调用函数,可以通过两种方式来传递参数:

传递类型 描述
值传递 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

值传递:传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

/* 定义交换值函数*/
func swap(x *int, y *int) {
   var temp int
   temp = *x    /* 保持 x 地址上的值 */
   *x = *y      /* 将 y 值赋给 x */
   *y = temp    /* 将 temp 值赋给 y */
}
   /* 调用 swap() 函数
   * &a 指向 a 指针,a 变量的地址
   * &b 指向 b 指针,b 变量的地址
   */

默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

3.3 函数用法

函数用法 描述
函数作为另外一个函数的实参 函数定义后可作为另外一个函数的实参数传入
闭包 闭包是匿名函数,可在动态编程中使用
方法 方法就是一个包含了接受者的函数

方法:Go 语言中同时有函数和方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。

语法:

func (variable_name variable_data_type) function_name() [return_type]{
   /* 函数体*/
}

例子: 

package main

import (
   "fmt"  
)

/* 定义结构体 */
type Circle struct {
  radius float64
}

func main() {
  var c1 Circle
  c1.radius = 10.00
  fmt.Println("圆的面积 = ", c1.getArea())
}

//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
  //c.radius 即为 Circle 类型对象中的属性
  return 3.14 * c.radius * c.radius
}

四、Go语言变量作用域

Go也是分为局部变量(函数内定义的变量)、全局变量(函数外定义的变量)、形式参数(函数定义中的变量称为形式参数)

注意:

1.Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。

五、Go语言数组

5.1 声明数组

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:

var variable_name [SIZE] variable_type

以上为一维数组的定义方式。例如以下定义了数组 balance 长度为 10 类型为 float32:

var balance [10] float32

5.2 初始化数组

以下演示了数组初始化:

var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

我们也可以通过字面量在声明数组的同时快速初始化数组:

balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:

var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
或
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

如果设置了数组的长度,我们还可以通过指定下标来初始化元素:

//  将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0,3:7.0}

5.3 多维数组

Go 语言支持多维数组,以下为常用的多维数组声明方式:

var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type

以下实例声明了三维的整型数组:

var threedim [5][10][4]int

例子:

package main

import "fmt"

func main() {
    // Step 1: 创建数组
    values := [][]int{}

    // Step 2: 使用 append() 函数向空的二维数组添加两行一维数组
    row1 := []int{1, 2, 3}
    row2 := []int{4, 5, 6}
    values = append(values, row1)
    values = append(values, row2)

    // Step 3: 显示两行数据
    fmt.Println("Row 1")
    fmt.Println(values[0])
    fmt.Println("Row 2")
    fmt.Println(values[1])

    // Step 4: 访问第一个元素
    fmt.Println("第一个元素为:")
    fmt.Println(values[0][0])
}

六、Go语言指针

6.1 定义指针

一个指针变量指向了一个值的内存地址。

类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:

var var_name *var-type

var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。以下是有效的指针声明:

var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */

6.2 空指针

当一个指针被定义后没有分配到任何变量时,它的值为 nil。

nil 指针也称为空指针。

nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。

一个指针变量通常缩写为 ptr

空指针判断:

if(ptr != nil)     /* ptr 不是空指针 */
if(ptr == nil)    /* ptr 是空指针 */

6.3 Go指针更多内容

内容 描述
Go 指针数组 你可以定义一个指针数组来存储地址
Go 指向指针的指针 Go 支持指向指针的指针
Go 向函数传递指针参数 通过引用或地址传参,在函数调用时可以改变其值

6.4 指针数组

package main

import "fmt"

const MAX int = 3

func main() {
   a := []int{10,100,200}
   var i int
   var ptr [MAX]*int;

   for  i = 0; i < MAX; i++ {
      ptr[i] = &a[i] /* 整数地址赋值给指针数组 */
   }

   for  i = 0; i < MAX; i++ {
      fmt.Printf("a[%d] = %d\n", i,*ptr[i] )
   }
}

/*
a[0] = 10
a[1] = 100
a[2] = 200
*/

6.5 指向指针的指针

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。

当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:

指向指针的指针变量声明格式如下:

var ptr **int;
package main

import "fmt"

func main() {

   var a int
   var ptr *int
   var pptr **int

   a = 3000

   /* 指针 ptr 地址 */
   ptr = &a

   /* 指向指针 ptr 地址 */
   pptr = &ptr

   /* 获取 pptr 的值 */
   fmt.Printf("变量 a = %d\n", a )
   fmt.Printf("指针变量 *ptr = %d\n", *ptr )
   fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
}

/*
变量 a = 3000
指针变量 *ptr = 3000
指向指针的指针变量 **pptr = 3000
*/

//三级指针(后续以此类推)
    var a int = 5
    // 指针
    var p1 *int = &a
    // 二级指针
    var p2 **int = &p1
    // 三级指针
    var p3 ***int = &p2

七、Go语言结构体

Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。

结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。

7.1 定义结构体

结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:

type struct_variable_type struct {
   member definition
   member definition
   ...
   member definition
}

一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:

variable_name := structure_variable_type {value1, value2...valuen}
或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}

例子:

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}


func main() {

    // 创建一个新的结构体
    fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})

    // 也可以使用 key => value 格式
    fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})

    // 忽略的字段为 0 或 空
   fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
}

7.2 访问结构体成员

如果要访问结构体成员,需要使用点号 . 操作符,格式为:

//结构体.成员名

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   fmt.Printf( "Book 1 title : %s\n", Book1.title)
   fmt.Printf( "Book 1 author : %s\n", Book1.author)
   fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
   fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)

   /* 打印 Book2 信息 */
   fmt.Printf( "Book 2 title : %s\n", Book2.title)
   fmt.Printf( "Book 2 author : %s\n", Book2.author)
   fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
   fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
}

7.3 结构体作为函数参数

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   printBook(Book1)

   /* 打印 Book2 信息 */
   printBook(Book2)
}

func printBook( book Books ) {
   fmt.Printf( "Book title : %s\n", book.title)
   fmt.Printf( "Book author : %s\n", book.author)
   fmt.Printf( "Book subject : %s\n", book.subject)
   fmt.Printf( "Book book_id : %d\n", book.book_id)
}

7.4 结构体指针

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   printBook(Book1)

   /* 打印 Book2 信息 */
   printBook(Book2)
}

func printBook( book Books ) {
   fmt.Printf( "Book title : %s\n", book.title)
   fmt.Printf( "Book author : %s\n", book.author)
   fmt.Printf( "Book subject : %s\n", book.subject)
   fmt.Printf( "Book book_id : %d\n", book.book_id)
}

注意:使用结构体的时候需要注意的点:定义的结构体如果只在当前包内使用,结构体的属性不用区分大小写。如果想要被其他的包引用,那么结构体的属性的首字母需要大写。 

package mode

//结构体小写开头的属性只能包内调用
type Books struct {   
    Title string   
    Author string   
    Subject string   
    book_id int
}
当该结构体被引用时:

import (   
    "fmt"   
    "src/mode"
)

func main() {
   var Book1 mode.Books        /* 声明 Book1 为 Books 类型 */

   /* book 1 描述 */
   Book1.Title = "Go 语言"
   Book1.Author = "www.runoob.com"
   Book1.Subject = "Go 语言教程"

   // 如果进行了如下调用,则会报错
   // Book1.book_id = 6495407

   /* 打印 Book1 信息 */
   printBook(Book1)

}

func printBook( book Books ) {
   fmt.Printf( "Book title : %s\n", book.Title)
   fmt.Printf( "Book author : %s\n", book.Author)
   fmt.Printf( "Book subject : %s\n", book.Subject)

   // 无法调用 book_id是小写
   // fmt.Printf( "Book book_id : %d\n", book.book_id)
}

猜你喜欢

转载自blog.csdn.net/qq_43681154/article/details/127382479