Go语言学习之分支、函数、指针、结构体 - 理解篇

《基础篇》《入门篇》当中,我们已经知道了Golang的基本属性、方法等知识,接下来,在本文当中就详细介绍一下Go中的一些常用操作和语法函数,包含下面几个内容。相信阅读完后续章节的朋友,就能大致对Go语言的项目开发有了一个基础的掌握。

为响应交流的朋友反馈篇幅过长的问题,本主尽量分开不同的知识点(PS:勤快点,别懒了),细致短促的讲解Go当中的知识点,以便朋友更加深入的学习。

- 分支、循环 

- 函数

- 指针

- 结构体

1、分支、循环

(1) if 语句

语法格式如下:(与java类似,区别在于它的条件不需要括号"()")

if expression(表达式) {
   /* 为 true 时执行 */
} else if expression2 {
   /* 为 false ,expression2为true时执行 */
} else{
   /* 都为false时,执行*/
}

示例:

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

   /* 使用 if 语句判断布尔表达式 */
   if a < 5 {
       /* 如果条件为 true 则执行以下语句 */
       fmt.Printf("a 小于 5\n" )
   }
   fmt.Printf("a 的值为 : %d\n", a)
}

(2)switch 语句

语法格式如下:(与java类似,区别在于Go中不需要像java一样在每一个case当中显式声明break,当找到匹配项时自动跳出)

switch var1 {  // var1可以是任意类型
    case val1: // 可以是同类型的任意值
        ...
    case val2: // 且必须是相同的类型
        ...
    default:
        ...
}

示例:

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var name string = "bboyHan"
   var salary int = 30
   //方式一:
   switch age {
      case 30000: name = "Tom"
      case 25000: name = "Jerry"
      case 22000,25000,30 : name = "bboyHan"  //case 后可以由多个数值
      default: name = "unknown"
   }
   //方式二:
   switch {
      case name == "Tom" :
         fmt.Printf("good man!\n" )
      case name == "Jerry", name == "bboyHan" :
         fmt.Printf("lazy man\n" )
      case name == "Kimi" :
         fmt.Printf("good woman\n" )
      case name == "Tomy":
         fmt.Printf("a dog\n" )
      default:
         fmt.Printf("unknown\n" );
   }
   fmt.Printf("He(She) is a %s \n", name );

注意点:case定义的常量不可以重复,case后可以有多个常量值。另外,case中的表达式是可选的,可以省略。如果该表达式被省略,则被认为是switch true,并且每个case表达式都被计算为true,并执行相应的代码块。

func main() {
    num := 75
    switch { 
    case num >= 0 && num <= 50:
        fmt.Println("num is greater than 0 and less than 50")
    case num >= 51 && num <= 100:
        fmt.Println("num is greater than 51 and less than 100")
    case num >= 101:
        fmt.Println("num is greater than 100")
    }
}

(3)select 语句

select会随机执行一个可运行的case。如果没有case可运行,它将会阻塞,直到有case可运行。通常可以使用在通信之上,比如接收和发送消息,生产者与消费者的关系等等。如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行。记住!其它的是不会执行。

package main

import "fmt"

func main() {
   var c1, c2, c3 chan int //定义通信通道
   var i1, i2 int
   select {
      case i1 = <-c1:
         fmt.Printf("接收消息:received ", i1, " from c1\n")
      case c2 <- i2:
         fmt.Printf("发送消息:sent ", i2, " to c2\n")
      case i3, ok := <-c3:
         if ok {
            fmt.Printf("接收消息:received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed - 消息关闭\n")
         }
      default:
         fmt.Printf("no communication - 未连接 \n")
   }
}

2、循环语句

Golang当中,for是唯一的循环语句,并不像java一样还有while、dowhile等语法,显得更加简单明了。

语法结构:

for init; condition; post {
    //执行内容
}

// init : 初始化语句,只执行一次
// condition : 判断条件
// post : 迭代后执行的语句

// init、condition、post 三部分都可以省略,可以选择,如:
for condition { }

for { }

示例:

package main

import "fmt"

func main() {
	nums := []int{1, 2, 3}
	sum := 0
	for _, num := range nums {  // 埋雷, orz,想知道"_"时什么意思请往下看
		sum += num
	}
	fmt.Println(sum)
	for i, num := range nums {
		if num == 2 {
			fmt.Println(i)
		}
	}

	kvs:= map[string]string{"a":"apple","b":"banana"}
	for k,v := range kvs{
		fmt.Printf("%s - %s\n",k,v)
	}

	for i,c := range "go"{
		fmt.Println(i,c) // 打印字符ASCII值
	}
}

其中还有break、continue跳出循环语句的使用,与其它语言类似

//continue
func main() {
    for i := 1; i <= 10; i++ {
        if i%2 == 0 {
            continue //跳出本次循环
        }
        fmt.Printf("%d ", i)
    }
}

//break
func main() {
    for i := 1; i <= 10; i++ {
        if i > 5 {
            break //当大于5时,结束循环
	}
        fmt.Printf("%d ", i)
    }
    fmt.Printf("\nline after for loop")
}
另外,Go中还有一个 goto 语句,可以无条件地 转移到过程中指定的行

func main() {
	var a int
A:
	for a < 5 {
		if a == 3 {
			a++
			goto A  //当执行到这时,返回到第3行继续执行代码
		}
		fmt.Printf("%d, --- \n", a)
		a++
	}
}

2、函数

我在《入门篇》提到过一个Go语言当中必不可少的函数,就是main函数,所谓函数,就是执行特定任务的代码块,在Go中,函数定义比较有趣的一点就是,它可以有多个返回值,十分方便

(1)语法格式:

func funcName(param1 type1, param2 type2) (output1 type1, output2 type2) {
	//...
	//函数具体实现内容
	//返回多个值
	return value1, value2
}

示例:(定义两个数交换的函数)

func swap(i int, i2 int) (int, int) {
	return i2,i
}

//输入3、5,得出结果5,3
func main() {
	a,b := swap(3,5)
	fmt.Println(a,b)
}

扫雷:上文当中出现了Go当中一个有趣的标识符,就是空白标识符"_",它的作用是可以代替任何类型的任何值。同时,它的作用还可以被当作一个占位符表示,在后续的函数方法当中不使用其值的情况下,就可以使用"_"来代替。

就像在上面的例子当中求数组[1,2,3]的和时,不需要使用索引的值,就使用了空白标识符

(3)可变参数

另外,Go同样支持可变参数的传递

示例:(定义一个函数,遍历并输出)

func numFunc(arg ...int) {
	for _, n := range arg {
		fmt.Printf("The number is: %d\n", n)
	}
}

(2) 函数可作为变量

在Go中,函数也是一种变量,我们可以通过type来定义它,在下文介绍的结构体中实例具体阐述。

type count int

func NewCount(i int) count {
	return count(i)
}

func main() {
	c := NewCount(10)
	fmt.Println(c)
}

3、指针

在函数当中,我们也听说过值传递和引用传递,在Go中,引入了一个指针的概念。所谓指针,就是指变量在内存当中,是存放于一个地址上的,修改变量实际是修改变量地址处的内存。

传递指针,其实就是引用的传递,那就让我们来看看如何定义指针的吧

语法格式:

var a *int // 使用"*",定义指针类型
var b = &a // 使用"&",接收a的地址

示例:

func main() {
	var i int
	var ptr *int
	var pptr **int
	i = 10
	ptr = &i    //接收i的地址值
	pptr = &ptr //接收ptr的地址值
	fmt.Printf("%d\n", i)
	fmt.Printf("%d\n", *ptr)
	fmt.Printf("%d\n", **pptr)
}


4、结构体

(1)接口

接口,即一组方法签名,当类型为接口中定义的方法进行实现时,就可以称之为实现了一个接口。在java当中我们也有面向对象的概念,这与OOP的概念十分相似,接口指定了类型应该具有的方法,类型决定了如何实现这些方法。

语法结构:

// 定义接口
type interface_name interface {
	method1 [return_type]
	method2 [return_type]
	method3 [return_type]
	...
	methodN [return_type]
}

// 定义结构体 
type struct_name struct {
	...
}

// 实现接口方法 
func (struct_name_variable struct_name) method_name1() [return_type] {
	// 方法实现
	...
}
func (struct_name_variable struct_name) method_namen() [return_type] {
	// 方法实现
	...
}

示例:

package main

import "fmt"

type dosomething interface {
	work() int
	study() int
}

type Student struct {
	name string
	age  int
}

func (stu Student) work() int {
	fmt.Printf("name:%s,age:%d -- work\n", stu.name, stu.age)
	return 3
}

func (stu Student) study() {
	fmt.Printf("name:%s,age:%d -- study\n", stu.name, stu.age)
}

func main() {
	s1 := new(Student)
	s1.name = "zhang san"
	s1.age = 23
	s2 := new(Student)
	s2.name = "Li si"
	s2.age = 23

	i := s1.work  // 作为变量使用
	a := i()
	fmt.Println(a)
	s2.study()
}

我们知道,在java当中,有一个类叫做Object,且认为所有的类都继承实现了Object类,作为java当中的顶级存在。在Go中,虽然没有继承这一概念,但同样的,也认为任意的类型都实现了空interface(我们这样定义:interface{}),也就是包含0个method的interface。

注意点:

1、接口对象不能调用实现对象的属性

2、interface可以被任意的对象实现

3、一个对象可以实现任意多个interface

4、interface的变量可以持有任意实现该interface类型的对象


----------------------------------------------------------------------

后续章节,敬请期待......

有任何建议或问题,欢迎加微信一起学习交流,欢迎从事IT,热爱IT,喜欢深挖源代码的行业大牛加入,一起探讨。

个人微信号:bboyHan



猜你喜欢

转载自blog.csdn.net/han0373/article/details/80421490