Go语言入门教程_go语言开发

Go语言入门教程_go语言开发首先函数的格式是固定的 func 函数名 参数 返回值 可选 函数体

大家好,欢迎来到IT知识分享网。

[length]type{0,0,0…} 
4.1.9切片类型

切片(slice)与数组一样也是可以若干相同类型元素的容器。与数组不同的是切片类型的长度不确定。每个切片值都会将数组作为其底层数据结构。表示切片类型的字面量如:

[]int 

或者是:

[]string 

切片类型的声明可以这样:

type MySlice []int 

对切片值的表示也与数组值相似

[]int{1,2,3} 

操作数组值的方法同样适用于切片值。还有一种操作数组的方式叫做“切片”,实施切片操作的方式就是切片表达式。例:

var number3 = [5]int{1,2,3,4,5} var slice1 = numbers3[1:4] 
var slice2 = slice1[1:3] 

除了长度切片值以及数组值还有另外一个属性–容量。数组的容量总是等于其长度,而切片值的容量往往与其长度不同。

个切片值的容量即为它的第一个元素值在其底层数组中的索引值与该数组长度的差值的绝对值。可以使用cap()内建函数获取数组、切片、通道类型的值的容量:

var capacity2 int = cap(slice2) 

切片类型属于引用类型,它的零值即为nil,即空值。如果我们只声明了一个切片类型而不为它赋值,则它的默认值 nil。

切片的更多操作方法有些时候我们可以在方括号中放入第三个正整数。如下图所示:

numbers3[1:4:4] 

第三个正整数为容量上界索引,它意义在于可以把作为结果的切片值的容量设置的更小。它可以限制我们通过这个切片值对其底层数组中的更多元素的访问。上节中numbers3和slice的赋值语句如下:

var numbers3 = [5]int{1,2,3,4,5} var slice1 = numbers3[1:4] 

这时,变量slice1的值是[]int{2,3,4}。但是我们可以通过如下操作将其长度延展与其容量相同:

slice1 = slice1[:cap(slice1)] 
var slice1 = numbers3[1:4:4] 
slice1 = append(slice1, 6, 7) 

通过上述操作,slice1的值变为了[]int{2,3,4,6,7}。一旦扩展操作超出了被操作的切片值的容量,那么该切片的底层数组就会被替换 最后一种操作切片的方式是“复制”。该操作的实施方法是调用copy函数。该函数接收两个类型相同的切片值作为参数,并把第二个参数值中的元素复制到第一个参数值中的相应位置(索引值相同)上。这里有两点需要注意:

  1. 这种复制遵循最小复制原则,即:被复制的元素的个数总是等于长度较短的那个参值的长度。
  2. 与append函数不同,copy函数会直接对其第一个参数值进行修改。

例:

var slice4 = []int{0,0,0,0,0,0} copy(slice4, slice1) 

通过上述复制操作,slice4会变成[]int{2,3,4,6,7,0,0}。

4.1.10 字典类型

Go语言的字典(Map)类型是一个哈希表的实现。字典类型的字面量如下:

map[K]T 

其中,”K”为键的类型,而”T”则代表元素(值)的类型。如果我们描述一个键类型为int,值类型为string的字典类型的话:

map[int]string 

字典的键类型必须是可比较的,否则会引起错误,即键不能是切片、字典、函数类型

字典值的字面量表示法实际上与数组的切片的字面量表示法很相似。最左边仍然是类型字面量,右边紧挨着由花括号包裹且有英文逗号分隔的键值对。每个键值对的键和值之间由冒号分隔。以字典类型map[int]string为例。他的值的字面量可以是这样的:

map[int]string{1:"a",2:"b"m,3:"c"} 

我们可以把这个值赋给一个变量

mm := map[int]string{1:"a",2:"b",3:"c"} 

可用索引表达式取出字典中的值:

b := mm[2] 

可以用索引表达式赋值:

mm[2] = b + "2" 

这样mm中键为2的值变为了”b2″。可以用如下方式向字典中添加一个键值对:

mm[4] = "" 

对于字典值来说,如果指定键没有对应的值则默认为该类型的空值。所以mm[5]会返回一个”“。但是这样的话我们就不知道mm[5]到底是””还是mm[5]没有这个值。所以go提供了另外一种写法:

e, ok := mm[5] 

针对字典的索引表达式可以有两个求职结果,第二个求职结果是bool类型的。它用于表明字典值中是否存在指定的键值对。 从字典中删除键值对的方法非常简单,仅仅是调用内建函数delete:

delete(mm, 4) 

无论mm中是否存在以4为键的键值对,delete都删除。 字典类型属于引用类型,它的零值即为nil

4.1.11 通道类型
chan T 
make(chan int, 5) 
ch1 := make(chan string, 5) 

这样一来,我们就可以使用接受操作符<-向通道值发送数据了。当然,也可以使用它从通道值接收数据,例如,如果我们要向通道ch1 发送字符串”value1″,那么应该这样做:

ch1 <- “value1" 

如果我们从ch1那里接收字符串,则要这样:

<- ch1 

我们可以把接受到字符串赋给一个变量,如:

value := <- ch1 

与针对字典值的索引表达式一样,针对通道值的接受操作也可以有第二个结果值:

value, ok := <- ch1 
close(ch1) 

对通道值的重复关闭会引发运行时异常,会使程序崩溃。在通道值有效的前提下,针对它的发送操作会在通道值已满(其中缓存的数据的个数已等于它的长度)时被阻塞。而向一个已被关闭的通道值发送数据会引发运行时异常。针对有效通道值的接收操作会在它已经为空时被阻塞。通道类型属于引用类型,它的零值为nil。

4.2 流程控制

4.2.1 条件控制

对应的关键字为if、 else和else if;

if a := 1; a >= 1 { fmt.Println("OK") } 
4.2.2 选择语句
switch i { case 0: fmt.Printf("0") case 1: fmt.Printf("1") case 2: fallthrough case 3: fmt.Printf("3") case 4, 5, 6: fmt.Printf("4, 5, 6") default: fmt.Printf("Default") } 
var a = 2 switch a { case 1: fmt.Println("this is case 1") case 2: fmt.Println("this is case 2") fallthrough default: fmt.Println("this is default") } // 输出结果如下: // this is case 2 // this is default 

以下是select、case的例子:

select { case communication clause : statement(s); case communication clause : statement(s); /* 你可以定义任意数量的 case */ default : /* 可选 */ statement(s); } 

以下描述了 select 语句的语法:

  • 每个 case 都必须是一个通信
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。
    否则:
    1. 如果有 default 子句,则执行该语句。
    2. 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。


4.2.3 循环语句

对应的关键字为for和range;

sum := 0 for i := 0; i < 10; i++ { sum += i } 
4.2.4 跳转语句
func myfunc() { i := 0 HERE: fmt.Println(i) i++ if i < 10 { goto HERE } } 

4.3 函数

4.3.1 概述

首先函数的格式是固定的,func+函数名+ 参数 + 返回值(可选) + 函数体。例 :

func main() { fmt.Println("Hello go") } 

在golang中有两个特殊的函数,main函数和init函数,main函数不用介绍在所有语言中都一样,它作为一个程序的入口,只能有一个。init函数在每个package是可选的,可有可无,甚至可以有多个(但是强烈建议一个package中一个init函数),init函数在你导入该package时程序会自动调用init函数,所以init函数不用我们手动调用,另外它只会被调用一次,因为当一个package被多次引用时,它只会被导入一次。

4.3.2 参数传递
  • 普通变量
    使用普通变量作为函数参数的时候,在传递参数时只是对变量值得拷贝,即将实参的值复制给变参,当函数对变参进行处理时,并不会影响原来实参的值。
  • 指针
    函数的变量不仅可以使用普通变量,还可以使用指针变量,使用指针变量作为函数的参数时,在进行参数传递时将是一个地址看呗,即将实参的内存地址复制给变参,这时对变参的修改也将会影响到实参的值。
  • 数组
    和其他语言不同的是,go语言在将数组名作为函数参数的时候,参数传递即是对数组的复制。在形参中对数组元素的修改都不会影响到数组元素原来的值。
  • slice, map, chan
    在使用slice, map, chan 作为函数参数时,进行参数传递将是一个地址拷贝,即将底层数组的内存地址复制给参数slice, map, chan 。这时,对slice, map, chan 元素的操作就是对底层数组元素的操作。
  • 函数名字
    在go语言中,函数也作为一种数据类型,所以函数也可以作为函数的参数来使用。
4.3.3 返回值

go语言可以返回局部变量的指针,因为go语言的回收机制是发现有被引用的栈上临时变量时,会自动存在堆上。

4.3.4 闭包

和其他语言类似,golang也支持闭包函数

package main import "fmt" func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) } } 

4.4 类

4.4.1 概述
type Poem struct { Title string Author string intro string } 

这样就声明了一个类,其中没有public、protected、private的的声明。golang用另外一种做法来实现属性的访问权限:属性的开头字母是大写的则在其它包中可以被访问,否则只能在本包中访问。类的声明和方法亦是如此

4.4.2 方法
func (poem *Poem) publish() { fmt.Println("poem publish") } 

或者

func (poem Poem) publish() { fmt.Println("poem publish") } 

和其它语言不一样,golang声明方法和普通方法一致,只是在func后增加了poem _Poem这样的声明。加_和没有加*的区别在于一个是传递指针对象,一个是传递值对象。

注意当创建了方法1后将会默认创建出方法2,反之则不会。

4.4.3 类的实例化

实例化对象有好几种方式

poem := &Poem{} poem.Author = "Heine" poem2 := &Poem{Author: "Heine"} poem3 := new(Poem) poem3.Author = "Heine" poem4 := Poem{} poem4.Author = "Heine" poem5 := Poem{Author: "Heine"} 

实例化的时候可以初始化属性值,如果没有指明则默认为系统默认值。

4.4.4 伪继承

golang中不存在继承,但可以使用组合的方式达到类似的效果.

func (e *Poem) ShowTitle() { fmt.Printf(e.Title) } type Poem struct { Title string Author string intro string } type ProsePoem struct { Poem Author string } 

ProsePoem属性中声明了Poem,表示组合了Poem的属性和方法(属性和方法都会被继承)。

prosePoem := &ProsePoem{ Poem: Poem{ Title: "Jack", Author: "slow", intro: "simple", }, Author: "test", } 

如果其中属性有冲突,则以外围的为主,也就是说会被覆盖。

type ProsePoem struct { Poem Author string } 

当访问Author的时候默认为ProsePoem的Author,如果需要访问Poem的Author属性可以使用
prosePoem.Poem.Author来访问方法同理

prosePoem := &ProsePoem{} prosePoem.Author = "Shelley" prosePoem.Poem.Author = "Heine" fmt.Println(prosePoem) 

从输出中可以很直观看到这一点。

&{ 
  { Heine } Shelley} 

4.5 接口

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

 Title: "Jack", Author: "slow", intro: "simple", }, Author: "test", } 
 如果其中属性有冲突,则以外围的为主,也就是说会被覆盖。 
 当访问Author的时候默认为ProsePoem的Author,如果需要访问Poem的Author属性可以使用 prosePoem.Poem.Author来访问方法同理。 

prosePoem := &ProsePoem{}

prosePoem.Author = “Shelley”

prosePoem.Poem.Author = “Heine”

fmt.Println(prosePoem)

 从输出中可以很直观看到这一点。 

&{
{ Heine } Shelley}

 4.5 接口 [外链图片转存中...(img-XlZxrOYO-77)] [外链图片转存中...(img-Gt5ZlOvY-78)] 网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/129965.html

(0)
上一篇 2025-08-20 16:20
下一篇 2025-08-20 16:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信