<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
            <title type="text">佐罗的博客</title>
    <updated>2021-09-25T23:57:59+08:00</updated>
        <id>http://www.zuxyu.com</id>
        <link rel="alternate" type="text/html" href="http://www.zuxyu.com" />
        <link rel="self" type="application/atom+xml" href="http://www.zuxyu.com/atom.xml" />
    <rights>Copyright © 2026, 佐罗的博客</rights>
    <generator uri="https://halo.run/" version="1.4.11">Halo</generator>
            <entry>
                <title><![CDATA[Go语言笔记（四）]]></title>
                <link rel="alternate" type="text/html" href="http://www.zuxyu.com/archives/go语言笔记四" />
                <id>tag:http://www.zuxyu.com,2021-09-24:go语言笔记四</id>
                <published>2021-09-24T23:03:08+08:00</published>
                <updated>2021-09-25T23:57:59+08:00</updated>
                <author>
                    <name>骑头猪逛街</name>
                    <uri>http://www.zuxyu.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<h1 id="错误处理">错误处理</h1><h2 id="错误处理捕获机制">错误处理/捕获机制：</h2><ul><li>go中追求代码的优雅，不使用try/catch。引用defer+recover机制处理</li><li>内置函数<code>recover</code>：允许程序管理恐慌<code>panic</code></li></ul><pre><code class="language-go">func main() {test()fmt.Println(&quot;上面的除法操作执行成功。。。&quot;)fmt.Println(&quot;正常执行下面的逻辑&quot;)}func test(){//利用defer+recover来捕获错误：defer func() {//调用recover内置函数，可以捕获错误：defer后加上匿名函数的调用err := recover()//如果没有捕获错误，返回值为零值，即：nilif err != nil {fmt.Println(&quot;错误已经捕获&quot;)fmt.Println(&quot;err是：&quot;,err)}}()num1 := 10num2 := 0result := num1/ num2fmt.Println(result)}</code></pre><ul><li>优点：提高程序健壮性</li></ul><h2 id="自定义错误">自定义错误</h2><ul><li>自定义错误：需要调用errors包下的New函数，函数返回error类型</li><li>示例:</li></ul><pre><code class="language-go">func main() {err := test()if  err != nil {fmt.Println(&quot;自定义错误：&quot;, err)}fmt.Println(&quot;上面的除法操作执行成功。。。&quot;)fmt.Println(&quot;正常执行下面的逻辑&quot;)}func test() (err error){num1 := 10num2 := 0if num2 == 0{//抛出自定义错误：return errors.New(&quot;除数不能为0&quot;)}else {result := num1/ num2fmt.Println(result)// 如果没有错误，返回零值return nil}}</code></pre><ul><li>有一种情况：程序出现错误以后，后续代码就没必要执行，想让程序中断，退出程序，需要借助buildin包下内置函数：<code>panic</code><ul><li>代码示例：</li></ul></li></ul><pre><code class="language-go">func main() {err := test()if  err != nil {fmt.Println(&quot;自定义错误：&quot;, err)panic(err)}fmt.Println(&quot;上面的除法操作执行成功。。。&quot;)fmt.Println(&quot;正常执行下面的逻辑&quot;)}func test() (err error){num1 := 10num2 := 0if num2 == 0{//抛出自定义错误：return errors.New(&quot;除数不能为0&quot;)}else {result := num1/ num2fmt.Println(result)// 如果没有错误，返回零值return nil}}</code></pre><h1 id="数组">数组</h1><h2 id="数组定义格式">数组定义格式</h2><ul><li><code>var 数组名 [数组大小]数组类型</code></li></ul><h2 id="数组内存分析">数组内存分析</h2><ul><li>示例</li></ul><pre><code class="language-go">func main() {//声明数组var arr [3]int16fmt.Println(len(arr))for i := 0; i &lt; 3; i++ {fmt.Println(arr[i])}//证明arr中存储的地址值fmt.Printf(&quot;arr的地址为：%p\n&quot;,&amp;arr)//第一个空间的地址：fmt.Printf(&quot;arr的地址为：%p\n&quot;,&amp;arr[0])//第二个空间的地址：fmt.Printf(&quot;arr的地址为：%p\n&quot;,&amp;arr[1])//第三个空间的地址：fmt.Printf(&quot;arr的地址为：%p\n&quot;,&amp;arr[2])}运行结果：3000arr的地址为：0xc000016092arr的地址为：0xc000016092arr的地址为：0xc000016094arr的地址为：0xc000016096</code></pre><ul><li>声明数组时，会在内存分配空间，且会添加对应数据类型的默认值</li><li>数组优点：访问/查询/读取 速度快</li><li>每个空间占用的字节数取决于数组类型</li></ul><h2 id="数组遍历">数组遍历</h2><h3 id="实现方式">实现方式</h3><ul><li>普通for循环</li><li>键值循环</li></ul><pre><code class="language-go">for key,val := range coll {    ...}</code></pre><pre><code>* coll就是你要的数组    * 每次遍历得到的索引用key接受，每次遍历得到的索引位置上的值用val* key，val的名字可随便起。* key，val是当前循环的局部变量* 如果想忽略某个值，使用`_`即可</code></pre><ul><li>示例</li></ul><pre><code class="language-go">func main() {// 给出5个学生的成绩，求出成绩的总和，平均数var scores [5]intfor i := 0; i &lt; len(scores) ; i++ {fmt.Printf(&quot;请录入第%d学生的成绩:&quot;, i +1)fmt.Scanln(&amp;scores[i])}sum := 0for i := 0; i &lt; len(scores); i++ {sum += scores[i]}//展示一下班级的每个学生的成绩：（数组进行遍历）//方式1：普通for循环：for i := 0; i &lt; len(scores); i++ {fmt.Printf(&quot;第%d个学生的成绩为：%d\n&quot;,i +1,scores[i])}fmt.Println(&quot;----------------------&quot;)//方式2：for-range循环for key, val := range scores {fmt.Printf(&quot;第%d个学生的成绩为：%d\n&quot;,key +1,val)}}运行结果：请录入第1学生的成绩:94 请录入第2学生的成绩:43请录入第3学生的成绩:86请录入第4学生的成绩:68请录入第5学生的成绩:96第1个学生的成绩为：94第2个学生的成绩为：43第3个学生的成绩为：86第4个学生的成绩为：68第5个学生的成绩为：96----------------------第1个学生的成绩为：94第2个学生的成绩为：43第3个学生的成绩为：86第4个学生的成绩为：68第5个学生的成绩为：96</code></pre><h2 id="数组的初始化方式">数组的初始化方式</h2><pre><code class="language-go">func main() {//第一种var arr1 [3]int = [3]int{3, 6, 9}fmt.Println(arr1)//第二种var arr2 = [3]int{1, 4, 7,}fmt.Println(arr2)//第三种var arr3 = [...]int{4,5,6,7}fmt.Println(arr3)//第四种:冒号前指的是下标var arr4 = [...]int{2: 66, 0: 33, 1: 99, 3: 88}fmt.Println(arr4)}</code></pre><h2 id="注意事项">注意事项</h2><ul><li>长度属于类型的一部分</li></ul><pre><code class="language-go">func main() {// 定义一个数组var arr1 = [3]int{3, 6, 9}fmt.Printf(&quot;数组的类型为：%T\n&quot;,arr1)var arr2 = [6]int{3, 6, 9, 1, 4, 7,}fmt.Printf(&quot;数组的类型为：%T\n&quot;,arr2)}运行结果：数组的类型为：[3]int数组的类型为：[6]int</code></pre><ul><li>Go中数组数值类型，在默认情况下是值传递，因此会进行值拷贝。</li></ul><pre><code class="language-go">func main() {var arr3 = [3]int{3, 6, 9}test1(arr3)fmt.Println(arr3)}func test1(arr [3]int) {arr[0] = 7}运行结果：[3 6 9]</code></pre><ul><li>如想在其他函数中，去修改原来的数组，可以使用引用传递（指针方式）</li></ul><h2 id="二维数组">二维数组</h2><h3 id="数组定义格式-1">数组定义格式</h3><ul><li><code>var 数组名 [数组大小][二维数组大小]数组类型</code></li><li>二维数组定义，有默认初始值，与数组一致</li></ul><h3 id="二维数组内存">二维数组内存</h3><ul><li>示例</li></ul><pre><code class="language-go">func main() {//定义二维数组var arr [2][3]int16fmt.Println(arr)fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr)fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr[0])fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr[0][0])fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr[1])fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr[1][0])}返回结果：func main() {//定义二维数组var arr [2][3]int16fmt.Println(arr)fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr)fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr[0])fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr[0][0])fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr[1])fmt.Printf(&quot;arr的地址是:%p\n&quot;,&amp;arr[1][0])}</code></pre><h3 id="二维数组遍历">二维数组遍历</h3><ul><li>二维数组遍历与一维数组一致即可以使用普通for循环，也可以键值循环</li><li>示例</li></ul><pre><code class="language-go">func main() {//定义二维数组var arr [3][3]int = [3][3]int{{1,4,7},{2,5,8},{3,6,9} }fmt.Println(arr)fmt.Println(&quot;----------&quot;)for i := 0; i &lt; len(arr);i++ {for j := 0; j &lt; len(arr[i]); j++ {fmt.Print(arr[i][j],&quot;\t&quot;)}fmt.Println()}fmt.Println(&quot;----------&quot;)for key,val := range arr {for key2,val2 := range val {fmt.Printf(&quot;arr[%v][%v]=%v\t&quot;,key,key2,val2)}fmt.Println()}}运行结果：[[1 4 7] [2 5 8] [3 6 9]]----------1       4       7       2       5       8       3       6       9       ----------arr[0][0]=1     arr[0][1]=4     arr[0][2]=7     arr[1][0]=2     arr[1][1]=5     arr[1][2]=8     arr[2][0]=3     arr[2][1]=6     arr[2][2]=9  </code></pre><h1 id="切片">切片</h1><h2 id="切片的引入">切片的引入</h2><ul><li>切片(<code>slice</code>）是Golang中一种独有的数据类型</li><li>数组有特定的用处，但是却有一些呆板（数组长度固定不可变），所在Go语言的代码里并不是特别常见。相对的切片却是随处可见的。切片是一种建立在数组类型之上的抽象，它构建在数组之上并且提供更强大的能力和便捷。</li><li>切片是对数组一个连续片段的引用，所以切片是一个引用类型。这个片段可以是整个数组，或者是由起始和终止索引标识的一些项的子集。需要注意的是，终止索引标识的项不包括在切片内。切片提供了一个相关数组的动态窗口。</li><li>切片的语法：</li></ul><pre><code class="language-go">var 切片名[]类型 = 数组的一个片段引用</code></pre><ul><li>示例：</li></ul><pre><code class="language-go">func main() {// 定义数组var intarr [6]int = [6]int{3, 6, 9, 1, 4, 7}//切片构建在数组之上//定义一个切片名字为slice,[]动态变化的数组长度不写,int类型,intarr是原数组//[1:3]切片 - 切出的一段片段 表示索引从1开始,到3结束,但不包含3//var slice []int = intarr[1:3]slice := intarr[1:3]//输出数组:fmt.Println(&quot;intarr:&quot;, intarr)//输出切片:fmt.Println(&quot;slice:&quot;, slice)//切片元素个数:fmt.Println(&quot;slice的元素个数为:&quot;,len(slice))//获取切片的容量:容量可以动态变化fmt.Println(&quot;slice的容量为:&quot;,cap(slice))}</code></pre><h2 id="内存分析">内存分析</h2><ul><li>切片有三个字段的数据结构：一个是指向底层数组的指针，一个是切片的长度，一个是切片的容量</li><li>代码示例</li></ul><pre><code class="language-go">func main() {// 定义数组var intarr [6]int = [6]int{3, 6, 9, 1, 4, 7}//切片构建在数组之上//定义一个切片名字为slice,[]动态变化的数组长度不写,int类型,intarr是原数组//[1:3]切片 - 切出的一段片段 表示索引从1开始,到3结束,但不包含3//var slice []int = intarr[1:3]slice := intarr[1:3]//输出数组:fmt.Println(&quot;intarr:&quot;, intarr)//输出切片:fmt.Println(&quot;slice:&quot;, slice)//切片元素个数:fmt.Println(&quot;slice的元素个数为:&quot;,len(slice))//获取切片的容量:容量可以动态变化fmt.Println(&quot;slice的容量为:&quot;,cap(slice))fmt.Printf(&quot;数组中下标为1位置的地址:%p\n&quot;,&amp;intarr[1])fmt.Printf(&quot;切片中下标为1位置的地址:%p\n&quot;,&amp;slice[0])slice[1] = 16fmt.Println(&quot;intarr:&quot;,intarr)fmt.Println(&quot;slice:&quot;,slice)}运行结果：func main() {// 定义数组var intarr [6]int = [6]int{3, 6, 9, 1, 4, 7}//切片构建在数组之上//定义一个切片名字为slice,[]动态变化的数组长度不写,int类型,intarr是原数组//[1:3]切片 - 切出的一段片段 表示索引从1开始,到3结束,但不包含3//var slice []int = intarr[1:3]slice := intarr[1:3]//输出数组:fmt.Println(&quot;intarr:&quot;, intarr)//输出切片:fmt.Println(&quot;slice:&quot;, slice)//切片元素个数:fmt.Println(&quot;slice的元素个数为:&quot;,len(slice))//获取切片的容量:容量可以动态变化fmt.Println(&quot;slice的容量为:&quot;,cap(slice))fmt.Printf(&quot;数组中下标为1位置的地址:%p\n&quot;,&amp;intarr[1])fmt.Printf(&quot;切片中下标为1位置的地址:%p\n&quot;,&amp;slice[0])slice[1] = 16fmt.Println(&quot;intarr:&quot;,intarr)fmt.Println(&quot;slice:&quot;,slice)}</code></pre><h2 id="切片的定义">切片的定义</h2><ul><li>定义一个切片，然后让切片去引用一个已经建好的数组</li></ul><pre><code class="language-go">var intarr [6]int = [6]int{3, 6, 9, 1, 4, 7}slice := intarr[1:3]</code></pre><ul><li>通过make内置函数来创建切片。基本语法：<code>var 切片名[type= make([],len,[cap])</code></li></ul><pre><code class="language-go">// 定义切片:make函数的三个参数:1.切片类型,2.切片长度,3.切片容量slice := make([]int,4, 20)fmt.Println(slice)fmt.Println(&quot;切片的长度:&quot;,len(slice))fmt.Println(&quot;切片的容量:&quot;,cap(slice))slice[0] = 66slice[1] = 88fmt.Println(slice)</code></pre><p>PS: make底层创建一个数组，对外不可见，所以不可以直接操作这个数组，要通过slice去间接的访问各个元素，不可以直接对数组进行操作/维护</p><ul><li>定一个切片，直接就指定具体数组，使用原理类似make的方式。</li></ul><pre><code class="language-go">slice2 := []int{1, 4, 7}fmt.Println(slice2)fmt.Println(&quot;切片的长度:&quot;,len(slice2))fmt.Println(&quot;切片的容量:&quot;,cap(slice2))</code></pre><h2 id="切片的循环">切片的循环</h2><pre><code class="language-go">func main() {// 定义切片:make函数的三个参数:1.切片类型,2.切片长度,3.切片容量slice := make([]int,4, 20)slice[0] = 66slice[1] = 88slice[2] = 99slice[3] = 100//方式1:普通for循环for i := 0; i &lt; len(slice); i++ {fmt.Printf(&quot;slice[%v]: %v\t&quot;, i, slice[i])}fmt.Println(&quot;\n---------------------&quot;)//方式2:for-range循环for i,v := range slice {fmt.Printf(&quot;下标:%v,元素:%v\n&quot;,i, v)}}</code></pre><h2 id="切片的注意事项">切片的注意事项</h2><ul><li>切片定义后不可以直接使用，需要让其引用到一个数组，或者make一个空间供切片来使用</li></ul><pre><code class="language-go">func main() {var slice []intfmt.Println(slice)//这样写法毫无意义}</code></pre><ul><li>切片使用不能越界</li></ul><pre><code class="language-go">func main() {var intarr [6]int = [6]int{1, 4, 7, 2, 5, 8}var slice []int = intarr[1:4]fmt.Println(slice[0])fmt.Println(slice[1])fmt.Println(slice[2])fmt.Println(slice[3])}运行结果：472panic: runtime error: index out of range [3] with length 3</code></pre><ul><li>简写方式：</li></ul><pre><code class="language-go">var slice = arr[0:end] ---&gt; var slice = arr[:end]//从0开始切，则可以省略开始部分var slice = arr[start:len(arr)] ---&gt; var slice = arr[start:]//切到最后，则可省略结束部分var slice = arr[0:len(arr)] ---&gt; var slice = arr[:]//从头切到尾，则可都省略</code></pre><ul><li>切片可以继续切片</li></ul><pre><code class="language-go">func main() {//切片再次切片var intarr [6]int = [6]int{1, 4, 7, 2, 5, 8}var slice []int = intarr[1:4]  //4,7,2var slice2 []int = slice[1:2]fmt.Println(slice2)slice2[0] = 66fmt.Println(slice)fmt.Println(slice2)fmt.Println(intarr)}</code></pre><ul><li>切片可以动态增长</li></ul><pre><code class="language-go">func main() {//定义数组:var intarr [6]int = [6]int{1, 4, 7, 3, 6, 9}//定义切片:var slice []int = intarr[1:4]fmt.Println(len(slice))slice2 := append(slice,88,50)fmt.Println(slice2)//底层原理://1.底层追加元素的时候对数组进行扩容,老数组扩容为新数组://2.创建一个新数组,将老数组中的4,7,3复制到新的数组中,在数组中增加88,50//3.slice2底层数组的指向,指向的是新数组//4.往往我们在使用追加的时候其实想做的效果给slice追加:slice = append(slice,88,50)fmt.Println(len(slice))//5.底层的新数组不能直接维护,不能直接维护,需要通过切片简介维护操作}</code></pre><p>PS：可以通过append函数将切片追加给切片</p><pre><code class="language-go">slice3 := []int{99,44}slice = append(slice,slice3...)fmt.Println(len(slice))</code></pre><ul><li>切片的拷贝</li></ul><pre><code class="language-go">func main() {//定义切片:var a []int = []int{1, 4, 7, 3, 6, 9}//在定义一个切片:var b []int = make([]int, 10)copy(b, a) //将a中对应数组中元素内容复制到b中对应的数组中,对应的是两个数组fmt.Println(b)}</code></pre><h1 id="映射">映射</h1><h2 id="映射说明">映射说明</h2><ul><li>映射（<code>map</code>):Go语言中内置的一种类型，它将键值对相关联，我们可以通过键<code>key</code>来获取对应的值<code>value</code>。类似其他语言的集合（如Java的HashMap）</li></ul><h2 id="基本语法">基本语法</h2><p><code>var map 变量名 map[keytype]valuetype</code><br />PS：key,value的类型：bool，数字，string，指针，channel、还可以包含前几个类型的接口、结构体、数组<br />PS：key通常为int，string类型，value通常为数字（整数，浮点数）、string、map、结构体<br />PS：key：slice、map、function不可以</p><h2 id="代码">代码</h2><ul><li>map的特点：<ul><li>map集合在使用前一定要make</li><li>make的key-value是无序的</li><li>key是不可以重复的，如果遇到重复，后一个value会替换前一个value</li><li>value是可以重复的</li></ul></li></ul><pre><code class="language-go">func main() {//定义map变量:var a map[int]string//只声明map内存是没有分配空间的//必须通过make函数进行初始化,才会分配空间:a = make(map[int]string, 10)a[1990] = &quot;张三&quot;a[1991] = &quot;李四&quot;a[1992] = &quot;王五&quot;a[1993] = &quot;王五&quot;a[1992] = &quot;赵六&quot;//输出集合fmt.Println(a)}运行结果：map[1990:张三 1991:李四 1992:赵六 1993:王五]</code></pre><h2 id="map的创建方式">map的创建方式</h2><pre><code class="language-go">func main() {//方式1://定义map变量:var a map[int]string//只声明map内存是没有分配空间的//必须通过make函数进行初始化,才会分配空间:a = make(map[int]string, 10)a[1990] = &quot;张三&quot;a[1991] = &quot;李四&quot;//输出集合fmt.Println(a)//方式2:可不设置长度b := make(map[int]string)b[1990] = &quot;张三&quot;b[1991] = &quot;李四&quot;fmt.Println(b)//方式3:c := map[int]string{1990: &quot;张三&quot;,1991: &quot;李四&quot;,}c[1992] = &quot;王五&quot;fmt.Println(c)}</code></pre><h2 id="map的操作">map的操作</h2><ul><li>增加和更新操作：<br /><code>map[&quot;key&quot;] = value --&gt; 如果key还没有就是增加，如果key存在就是修改</code></li><li>删除操作<br />delete(map,&quot;key&quot;),delete是一个内置函数，如果key存在，就删除该key-value，如果key不存在，不操作，但也不会报错</li><li>清空操作<ul><li>如果我们要删除map的所有key，没有一个专门的方法一次删除，可以遍历一下key，逐个删除</li><li>或者map = make(...)，make一个新的，让原来的成为垃圾，被gc回收</li></ul></li><li>查找操作</li></ul><pre><code class="language-go">value,bool = map[key]</code></pre><p>value为返回的value，bool为是否返回，要么true，要么false</p><h3 id="代码-1">代码</h3><pre><code class="language-go">func main() {b := make(map[int]string)//增加:b[1990] = &quot;张三&quot;b[1991] = &quot;李四&quot;//修改:b[1990] = &quot;王五&quot;//删除delete(b,1990)delete(b,1998) //如果key值不存在也不会报错fmt.Println(b)//查找:value, flag := b[19900]fmt.Println(value)fmt.Println(flag)fmt.Println(b)}func main() {b := make(map[int]string)//增加:b[1990] = &quot;张三&quot;b[1991] = &quot;李四&quot;b[1992] = &quot;王五&quot;//获取长度fmt.Println(len(b))//遍历:for k,v := range b {fmt.Printf(&quot;key为:%v,value为%v \t&quot;,k, v)}//加深难度:a := make(map[string]map[int]string)//赋值:a[&quot;班级1&quot;] = make(map[int]string, 3)a[&quot;班级1&quot;][1990] = &quot;张三&quot;a[&quot;班级1&quot;][1991] = &quot;李四&quot;a[&quot;班级1&quot;][1992] = &quot;王五&quot;a[&quot;班级2&quot;] = make(map[int]string, 3)a[&quot;班级2&quot;][2001] = &quot;小明&quot;a[&quot;班级2&quot;][2002] = &quot;小方&quot;a[&quot;班级2&quot;][2003] = &quot;小红&quot;for s, m := range a {fmt.Println(s)for k, v := range m {fmt.Printf(&quot;学号为: %v,学生姓名为:%v\t&quot;,k,v)}}}</code></pre><h1 id="面向对象">面向对象</h1><h2 id="面向对象的引入">面向对象的引入</h2><h3 id="golang语言面向对象编程说明">Golang语言面向对象编程说明</h3><ul><li>Golang也支持面向对象编程（OOP），但是和传统的面向对象编程有区别，并不是纯粹的面向对象语言。所以我们说Golang支持面向对象编程特性是比较准确的。</li><li>Golang没有类（class），Go语言的结构体（struct）和其他编程语言的类有同等的地位，你可以理解Golang是基于struct来实现OOP特性的。</li><li>Golang面向对象编程非常简洁，去掉了传统OOP语言的方法重载、构造函数和析构函数、隐藏的this指针等等</li><li>Golang仍然有面向对象编程的继承，封装和多态的特性，只是实现的方式和其他OOP语言不一样，比如继承：Golang没有extends关键字，继承是通过匿名字段来实现。</li></ul><h3 id="结构体的引入">结构体的引入</h3><ul><li>利用变量处理对象<ul><li>缺点：1、不利于数据的管理、维护。2、用变量管理太分散</li></ul></li><li>结构体</li></ul><pre><code class="language-go">// Teacher 定义老师的结构体,将老师中的各个属性,统一放入结构体中管理type Teacher struct{//变量名大写可访问这个属性Name stringAge intSchool string}</code></pre><h3 id="结构体实例创建">结构体实例创建</h3><ul><li>方式1</li></ul><pre><code class="language-go">func main() {var t1 Teachert1.Name = &quot;张三&quot;t1.Age = 45t1.School = &quot;清华大学&quot;fmt.Println(t1)</code></pre><ul><li>方式2</li></ul><pre><code class="language-go">func main() {var t1 Teacher = Teacher{&quot;张三&quot;,45,&quot;江阴学院&quot;}fmt.Println(t1)}</code></pre><ul><li>方式3</li></ul><pre><code class="language-go">func main() {//创建老师结构体的实例,对象,变量var t *Teacher = new(Teacher)// t是指针,t其实指向的就是地址,应该给这个地址的指向的对象的字段赋值;(*t).Name = &quot;张三&quot;(*t).Age = 31   //*的作用:根据地址取值//为了符合程序员的变成习惯.go提供了简化的赋值方式:t.School = &quot;江阴学院&quot; //go编译器底层对t.School转化(*t).School = &quot;江阴学院&quot;fmt.Println(*t)}</code></pre><ul><li>方式4</li></ul><pre><code class="language-go">func main() {//创建老师结构体的实例,对象,变量var t *Teacher = &amp;Teacher{&quot;张三&quot;,31,&quot;江阴学院&quot;}fmt.Println(*t)}</code></pre><h3 id="结构体之间转换">结构体之间转换</h3><ul><li>结构体是用户单独定义的类型，和其他类型进行转换时需要有完全相同的字段（名字、个数和类型）</li></ul><pre><code class="language-go">type Student struct{Age int}type Person struct{Age int}func main() {var s Student = Student{10}var p Person = Person{10}s = Student(p)fmt.Println(s)}</code></pre><ul><li>结构体进行type重新定义（相当于取别名），Golang认为是新的数据类型，但是互相可以强转</li></ul><pre><code class="language-go">type Student struct{Age int}type Stu Studentfunc main() {var s1 Student = Student{19}var s2 Stu = Stu{19}s1 = Student(s2)fmt.Println(s1)fmt.Println(s2)}</code></pre>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Go语言笔记（三）]]></title>
                <link rel="alternate" type="text/html" href="http://www.zuxyu.com/archives/go语言笔记三" />
                <id>tag:http://www.zuxyu.com,2021-09-09:go语言笔记三</id>
                <published>2021-09-09T23:09:21+08:00</published>
                <updated>2021-09-24T23:02:35+08:00</updated>
                <author>
                    <name>骑头猪逛街</name>
                    <uri>http://www.zuxyu.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<h1 id="函数">函数</h1><h2 id="为什么要用函数">为什么要用函数</h2><ul><li>提高代码的复用性，减少代码冗余，提高代码维护性</li></ul><h2 id="函数的定义">函数的定义</h2><ul><li>为完成某一功能的程序指令（语句）的集合，称为函数</li><li>对特定的功能进行提取，形成一个代码片段。</li></ul><h2 id="函数的说明">函数的说明</h2><ul><li>函数和函数是并列的关系，所以定义的函数不能写到main函数中</li></ul><h2 id="基本语法">基本语法</h2><pre><code class="language-go">func 函数名（形参列表） （返回值类型列表）{    执行语句    return + 返回值列表}</code></pre><h3 id="函数名">函数名</h3><ul><li>遵循标识符命名规范：见名知意，驼峰命名</li><li>首字母不能是数字</li><li>首字母大写该函数可以被本包文件和其他包文件使用（类型public）</li><li>首字母小写只能被本包文件使用，其他包文件不能使用（类似private）</li></ul><h3 id="形参列表">形参列表</h3><ul><li>形参列表：个数：可以是一个参数，可以是n个参数，可以是0个参数</li><li>形式参列表：作用：接受外来的数据</li><li>实际参数：实际传入的数据</li></ul><h3 id="返回值类型列表">返回值类型列表</h3><ul><li>函数的返回值对应的类型应该返回在返回值列表中</li><li>返回0个：返回值不写</li><li>返回1个：返回值中的()可以省略不写</li><li>返回多个：返回值中的()不可省略</li><li>如果有返回值不想接收。可使用<code>_</code>可忽略</li></ul><h3 id="注意事项">注意事项</h3><ul><li>函数名相同，形参列表不同叫重载，但Golang中不支持重载</li><li>Golang中支持可变参数（如果你希望函数带有可变数量的参数）</li></ul><pre><code class="language-go">//定义一个函数，函数的参数为：可变参数 ... 参数的数量可变// args...int 可以传入任意多个数量的int类型的数据，传入0个，1个。。。。n个func test(args...int){    //函数内部处理可变参数的时候。将可变参数当做切片来出来    for i:=0;i &lt;len(args);i++ {        fmt.Println(args[i])    }}</code></pre><ul><li>基本数据类型和数组默认都是值传递的。即进行值拷贝，在函数内修改不会影响原来的值</li><li>以值传递方式的数据类型，如果希望在函数内的数量能修改函数外的变量，可以传入变量的地址&amp;，函数内以指针的方式操作变量，以效果来看类似引用传递</li></ul><pre><code class="language-go">//参数的类型为指针func test(num *int){    //对地址对应的变量进行改变数值    *num = 30}func main(){    var num int = 10    fmt.Println(&amp;num)    test(&amp;num)    fmt.Println(num)}</code></pre><ul><li>函数也是一种数据类型，可以赋值给一个变量，则该变量就是一个函数类型的变量了。通过该变量可以对函数调用。</li></ul><pre><code class="language-go">func test(num int) {fmt.Println(num)}func main() {// 函数也是一种数据类型，可以赋值给一个变量a := test//变量就是一个函数类型的变量fmt.Printf(&quot;a的类型是:%T,test函数的类型是：%T\n&quot;,a, test)// 通过变量可以对函数调用a(10) // 等价于 test(10)}</code></pre><ul><li>函数既然是一种数据类型，因此在Go中也可以作为形参，并且调用（把函数本身当做一种数据类型）</li></ul><pre><code class="language-go">func test02(num1 int,num2 float32,testFunc func(int)) {fmt.Println(&quot;------test02&quot;)}func main() {// 函数也是一种数据类型，可以赋值给一个变量a := test//变量就是一个函数类型的变量fmt.Printf(&quot;a的类型是:%T,test函数的类型是：%T\n&quot;,a, test)// 通过变量可以对函数调用a(10) // 等价于 test(10)//调用test02函数test02(10,3.19, test)test02(10,3.19, a)}</code></pre><ul><li>为了简化数据类型定义，GO支持自定义数据类型</li></ul><pre><code class="language-go">基本语法：type 自定义数据类型 数据类型可以理解为起了一个别名type myFunc func(int)func test03(num1 int,num2 float32,testFunc myFunc){fmt.Println(&quot;------test02&quot;)}func main(){var num1 myInt = 30fmt.Println(&quot;num1为&quot;, num1)var num2 int = 30num2 = int(num1)  // 虽然是别名，但在go中编译识别时候还是认为myInt和int不是同一个数据类型fmt.Println(&quot;num1为&quot;, num2)test03(10,9.8, a)}</code></pre><ul><li>GO语言里支持对返回值进行定义<ul><li>传统写法要求：返回值和返回值的类型对应，顺序不能差</li></ul></li></ul><pre><code class="language-go">// 定义一个函数：求两个数的和、差func test04(num1 int, num2 int)(int,int) {result01 := num1 + num2result02 := num1 - num2return result01, result02}</code></pre><pre><code>* 返回值定义的则无需关心顺序</code></pre><pre><code class="language-go">// 定义一个函数：求两个数的和、差func test05(num1 int, num2 int)(sum int,sub int) {sum = num1 + num2sub = num1 - num2return}</code></pre><h2 id="调用案例">调用案例</h2><pre><code class="language-go">func cal(num1 int, num2 int) (int,int) {var sum int = 0sum += num1sum += num2var result int = num1 - num2return sum,result}func cal(num1 int, num2 int) int { //如果返回值类型就一个，那括号可省略不写。var sum int = 0sum += num1sum += num2return sum}func main() {sum, result := cal(20,10)fmt.Println(sum)}</code></pre><h2 id="内存分析">内存分析</h2><h3 id="栈堆代码区">栈、堆、代码区</h3><h4 id="栈通常会放基本数据类型">栈：通常会放基本数据类型</h4><ul><li>为每个函数开辟栈帧（开辟空间）</li><li>在函数执行后，程序会销毁函数对应开辟的栈空间（栈帧）</li></ul><h4 id="堆通常会放复杂数据类型">堆：通常会放复杂数据类型</h4><h4 id="代码区通常会放代码本身">代码区：通常会放代码本身</h4><h2 id="包的引入">包的引入</h2><h3 id="使用包的原因">使用包的原因</h3><ol><li>我们不可能把所有函数放到同一个源文件中，可以分门别类的把函数放在不同的分类中</li><li>解决同名问题：两个人都想定义一个同名的函数，在同一个文件中是不可以定义相同名字的函数，但可以用包来区分。</li></ol><pre><code class="language-go">package main  //1.package进行包的声明，建议：包的声明和这个包所在的文件夹同名// 2.main包是程序的入口包，一般main函数会放在这个包下//import &quot;fmt&quot;// 3. 包名是从$GOPATH/src后开始计算的。使用/进行路径分隔。//import &quot;testproject01/dbutils&quot;// 5.如果有多个包。可以一次性导入import (&quot;fmt&quot;&quot;testproject01/dbutils&quot;)func main() {fmt.Println(&quot;你好，这是main函数的这行&quot;)dbutils.GetConn()  //4.在函数调用的时候前面要定位到所在的包}</code></pre><h3 id="包的细节">包的细节</h3><ol><li>package进行包的声明，建议：包的声明这个包和所在的文件夹同名</li><li>main包是程序的入口包，一般main函数会放在这个包下。<ul><li>main函数已经要在main包下，否则不能编译执行</li></ul></li><li>打包语法：<code>package 包名</code>形式</li><li>引入包的语法：<code>import 包的路径</code><ul><li>包名是从<code>$GOPATH/src</code>后开始计算的。使用<code>/</code>进行路径分隔。</li></ul></li><li>如果有多个包建议一次性导入，格式如下</li></ol><pre><code class="language-go">  import(      &quot;fmt&quot;      &quot;testproject01/dbutils&quot;  )</code></pre><ol start="6"><li>在函数调用的时候前面要定位到所在的包</li><li>函数名、变量名首字母大写，才可被其他包访问</li><li>一个目录下不能有重复的函数，即使是不同文件下，但他们在同一个目录下。如果存在相同的函数名。则会报错。</li><li>包名和文件夹的名字，可以不一样。import引入的是包所在的文件夹的路径，函数前的定位用的是包名</li><li>一个目录下的同级文件归属于一个包<br /><code>同级别的源文件的包的声明必须一致</code></li><li>包到底是什么<ol><li>在程序层面，所有使用相同<code>package 包名</code>的源文件组成的代码模块</li><li>在源文件层面就是一个文件夹</li></ol></li><li>可以给包取别名，取别名后，原来的包名就不能使用了</li></ol><h2 id="init函数">init函数</h2><ul><li>init函数：初始化函数，可以用来进行一些初始化的操作<ul><li>每一个源文件都可以包含一个init函数，该函数会在main函数前，被GO运行框架调用</li></ul></li><li>全局变量定义、init函数、main函数都存在时是怎样的执行过程<ul><li>全局变量定义--&gt;init函数--&gt;main函数</li></ul></li><li>多个源文件都有init函数时，执行过程<ul><li>先执行main函数中import的包，包中如果有init函数先执行</li><li>以此类推，如果import的包中还有import的包则继续执行</li><li>最后才是当前main函数下的init函数</li></ul></li></ul><h2 id="匿名函数">匿名函数</h2><ul><li>Go支持匿名函数，如果我们某个函数只是希望使用一次，可以考虑使用匿名函数</li><li>匿名函数使用方式：<ul><li>在定义匿名函数时就直接调用，这种方式匿名函数只能调用一次（用的多）</li></ul><pre><code class="language-go">import &quot;fmt&quot;func main() {//定义匿名函数result := func (num1 int,num2 int)(int){return num1 + num2}(10, 20)fmt.Println(result)}</code></pre><ul><li>将匿名函数赋值给一个变量（该变量就是函数变量了）,再通过该变量来调用匿名函数,可重复调（用的比较少）</li></ul><pre><code class="language-go">func main() {//定义匿名函数result := func (num1 int,num2 int)(int){return num1 + num2}(10, 20)fmt.Println(result)// 将匿名函数赋给变量，这个变量实际就是函数类型为intsub := func (num1 int,num2 int)(int){return num1 - num2}result01 :=sub(30, 70)fmt.Println(result01)}</code></pre><ul><li>如何让一个匿名函数，可以将匿名函数给一个全局变量就可以了。</li></ul></li></ul><h2 id="闭包">闭包</h2><h3 id="什么是闭包">什么是闭包</h3><ul><li>闭包就是一个函数和其相关的引用环境组合的一个整体</li><li>案例</li></ul><pre><code class="language-go">// 函数功能：求和// 函数的名字： getSum 参数为空// getSum函数返回值为一个函数，这个函数的参数是一个int类型的参数，返回值也是int类型func getSum() func (int) int{var sum int = 0return func(num int) int {sum += numreturn sum}}//闭包：返回的匿名函数+匿名函数以外的变量numfunc main() {f := getSum()fmt.Println(f(1))//1fmt.Println(f(2))//3fmt.Println(f(3))//6fmt.Println(f(4))//10}</code></pre><p>总结：匿名函数中引用的变量会一直保存在内存中，可以一直使用</p><h3 id="闭包的本质">闭包的本质</h3><ul><li>闭包的本质依旧是一个匿名函数，只是这个函数引入外界的变量/参数即：<br /><code>匿名函数+引用的变量/参数=闭包</code></li></ul><h3 id="闭包的特点">闭包的特点：</h3><ul><li>返回的是一个匿名函数，但是这个匿名函数引用到函数外的变量/参数，因此这个匿名函数就和变量/参数形成一个整体，构成闭包。</li><li>闭包中使用的变量/参数会一直保存在内存中，所以会一直使用--&gt; 意味着闭包不可滥用（对内存消耗大）</li><li>不使用闭包时候：想保留的值，不可以反复使用</li><li>闭包应用场景：闭包可以保留上次引用的某个值，传一次即可反复使用</li></ul><h2 id="defer关键字">defer关键字</h2><ul><li>在函数中，程序员经常需要创建资源，为了在函数执行完毕后，及时释放资源。Go的设计者提供defer关键字</li><li>案例</li></ul><pre><code class="language-go">func main() {fmt.Println(add(30,60))}func add(num1 int,num2 int) int {//在Golang中，程序遇到defer关键字，不会立即执行defer后的语句，而是将defer后的语句压入一个栈中，继续执行函数后面的语句。defer fmt.Println(&quot;num1=&quot;, num1)defer fmt.Println(&quot;num2=&quot;, num1)// 栈的特点是：先进后出// 在函数执行完毕后，从栈中取出语句开始执行，按照先进后出的规则执行语句var sum int = num1 + num2fmt.Println(&quot;sum=&quot;, sum)return sum}</code></pre><ul><li>发现defer关键字，会将后面的代码语句压入栈中，也会将相关的值同时拷贝到栈中，不会随着函数后面的变化而变化</li><li>案例</li></ul><pre><code class="language-go">func main() {fmt.Println(add(30,60))}func add(num1 int,num2 int) int {//在Golang中，程序遇到defer关键字，不会立即执行defer后的语句，而是将defer后的语句压入一个栈中，继续执行函数后面的语句。defer fmt.Println(&quot;num1=&quot;, num1)defer fmt.Println(&quot;num2=&quot;, num2)num1 += 90 //num1:120num2 += 50 //num2:110// 栈的特点是：先进后出// 在函数执行完毕后，从栈中取出语句开始执行，按照先进后出的规则执行语句var sum int = num1 + num2fmt.Println(&quot;sum=&quot;, sum)return sum}</code></pre><h3 id="defer应用场景">defer应用场景</h3><p>如：关闭某个使用的资源，在使用的时候直接随手defer，因为defer有延迟执行机制（函数执行完毕再执行defer压入栈的语句，所以用完立即关闭，比较省心，省事</p><h2 id="系统函数">系统函数</h2><h3 id="字符串相关函数">字符串相关函数</h3><ul><li>内置函数不用导包，直接用即可。</li><li>案例</li></ul><pre><code class="language-go">import (&quot;fmt&quot;&quot;strconv&quot;&quot;strings&quot;)func main() {//1.统计字符串长度str := &quot;你好Golang&quot; //在golang中，汉字是utf-8字符集，一个汉字3个字节fmt.Println(len(str))//2.对字符串遍历r:=[]rune(str) //转成切片for i := 0; i &lt; len(r); i++ {fmt.Printf(&quot;%c\n&quot;,r[i])}//3.字符串转整数num1, _ := strconv.Atoi(&quot;666&quot;)fmt.Println(num1)//4. 整数转字符串str1 := strconv.Itoa(88)fmt.Println(str1)//5.查找子串是否在指定的字符串中strings.Contains(&quot;javaandgolang&quot;, &quot;go&quot;)//6.统计一个字符串有几个指定的字符串count := strings.Count(&quot;golangandjava&quot;, &quot;ga&quot;)fmt.Println(count)//7.不区分大小写的字符串比较flag := strings.EqualFold(&quot;hello&quot;, &quot;HELLO&quot;)fmt.Println(flag)//区分大小写的字符串比较fmt.Println(&quot;hello&quot;==&quot;Hello&quot;)//8.返回子串在字符串中第一次出现的索引值,存在返回索引值，不存在返回-1index := strings.Index(&quot;golangandjavaga&quot;,&quot;ga&quot;)fmt.Println(index)//9.字符串的替换str2 := strings.Replace(&quot;goandjavagogo&quot;,&quot;go&quot;,&quot;golang&quot;,-1)str3 := strings.Replace(&quot;goandjavagogo&quot;,&quot;go&quot;,&quot;golang&quot;,2)fmt.Println(str2)fmt.Println(str3)//n 可以指定要替换的次数//10.按照指定字符进行切割，返回一个字符串数组arr := strings.Split(&quot;go-python-java&quot;,&quot;-&quot;)fmt.Println(arr)//11.将字符串字母进行大小写fmt.Println(strings.ToLower(&quot;Go&quot;))fmt.Println(strings.ToUpper(&quot;Go&quot;))//12.字符串左右两边空格去除fmt.Println(strings.TrimSpace(&quot;     go and java     &quot;))//13.将字符串左右指定的字符去除fmt.Println(strings.Trim(&quot;~golang~&quot;,&quot;~&quot;))//14.将字符串左边的字符去掉fmt.Println(strings.TrimLeft(&quot;~golang~&quot;,&quot;~&quot;))//15.将字符串右边的字符去掉fmt.Println(strings.TrimRight(&quot;~golang~&quot;,&quot;~&quot;))//16.判断字符串是否以指定的字符串开头fmt.Println(strings.HasPrefix(&quot;http://localhost&quot;, &quot;http&quot;))//16.判断字符串是否以指定的字符串结尾fmt.Println(strings.HasSuffix(&quot;test.png&quot;, &quot;jpg&quot;))}</code></pre><h3 id="日期和时间相关函数">日期和时间相关函数</h3><ul><li>时间相关函数可以使用<code>time</code>包</li><li>案例</li></ul><pre><code class="language-go">import (&quot;fmt&quot;&quot;time&quot;)func main() {now := time.Now()//Now()返回的值是一个结构体，类型是：time.Timefmt.Printf(&quot;%v ~~~~类型为%T\n&quot;,now,now)//调用结构体中的方法：fmt.Printf(&quot;年：%v\n&quot;,now.Year())fmt.Printf(&quot;月：%v\n&quot;,int(now.Month())) //月就变成数字，默认是fmt.Printf(&quot;日：%v\n&quot;,now.Day())fmt.Printf(&quot;时：%v\n&quot;,now.Hour())fmt.Printf(&quot;分：%v\n&quot;,now.Minute())fmt.Printf(&quot;秒：%v\n&quot;,now.Second())fmt.Println(&quot;--------------------1-----------------------------&quot;)//将字符串直接输出fmt.Printf(&quot;当前年月日：%d-%d-%d 时分秒：%d-%d-%\n&quot;,now.Year(),now.Month(),now.Day(),now.Hour(),now.Minute(),now.Second())//Sprintf可以得到这个字符串以便后续使用。dateStr := fmt.Sprintf(&quot;当前年月日：%d-%d-%d 时分秒：%d-%d-%d&quot;,now.Year(),now.Month(),now.Day(),now.Hour(),now.Minute(),now.Second())fmt.Println(dateStr)fmt.Println(&quot;----------------------2---------------------------&quot;)//这个参数字符串的各个数字必须是固定的，必须这样写dateStr2 := now.Format(&quot;2006/01.02 15/04/05&quot;)fmt.Println(dateStr2)//选择任意的组合都是可以的，根据需求自己选择dateStr3 := now.Format(&quot;2006 01.02&quot;)fmt.Println(dateStr3)}</code></pre><h3 id="内置函数">内置函数</h3><h4 id="什么是内置函数">什么是内置函数</h4><ul><li>Golang设计者为了编程方便，提供了一些函数，这些函数不用导包可以直接使用，我们称为Go的内置函数/内建函数</li></ul><h4 id="内置函数存放位置">内置函数存放位置</h4><ul><li>builtin包下，直接用即可，不用引包</li></ul><h4 id="常用函数">常用函数</h4><ul><li>len函数：统计字符串长度</li><li>new函数：用于分配内存，主要用来分配值类型（int系列、float系列、bool、string、数组和结构体struct）</li></ul><pre><code class="language-go">func main() {//new分配内存，new函数的实参是一个类型而不是具体是数值，返回值是对应类型的指针num: *intnum := new(int)fmt.Printf(&quot;num的类型是：%T,num的值是：%v，num地址是：%v，num指针指向的值是：%v&quot;, num,num,&amp;num,*num)}</code></pre><ul><li>make函数：用于分配内存，主要用来分配引用类型（指针、slice切片、map、管道chan、interface等）</li></ul>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Go语言笔记（二）]]></title>
                <link rel="alternate" type="text/html" href="http://www.zuxyu.com/archives/go语言笔记二" />
                <id>tag:http://www.zuxyu.com,2021-08-19:go语言笔记二</id>
                <published>2021-08-19T23:37:59+08:00</published>
                <updated>2021-09-13T22:03:37+08:00</updated>
                <author>
                    <name>骑头猪逛街</name>
                    <uri>http://www.zuxyu.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<h1 id="流程控制">流程控制</h1><h2 id="流程控制的作用">流程控制的作用</h2><p>流程控制语句是用来在控制程序中各语句执行顺序的语句，可以把语句组合成能完成一定功能的小逻辑模块。</p><h2 id="控制语句的分类">控制语句的分类：</h2><ol><li>顺序结构</li><li>分支结构</li><li>循环结构</li></ol><h2 id="分支结构">分支结构</h2><h3 id="if分支">if分支</h3><h4 id="if单分支">if单分支</h4><p>条件表达式左右的()括号可省略：</p><pre><code class="language-go">if 条件表达式{    逻辑代码}</code></pre><p>PS：在Golang里if后面可以并列的加入变量的定义</p><pre><code class="language-go">if count :=20;count &lt; 20{    fmt.Println(&quot;aaaaa&quot;)}</code></pre><h4 id="if双分支">if双分支</h4><pre><code class="language-go">if 条件表达式{    逻辑代码1} else {    逻辑代码2}</code></pre><h4 id="if多分支">if多分支</h4><pre><code class="language-go">if 条件表达式{    逻辑代码1} else if {    逻辑代码2} else if {    逻辑代码3} else {    逻辑代码4}</code></pre><h3 id="switch分支">switch分支</h3><h4 id="基本语法">基本语法</h4><pre><code class="language-go">switch 表达式{    case 值1,值2,....:语句块1    case 值3,值4,....:语句块2    default: 语句块}</code></pre><h4 id="注意事项">注意事项</h4><ul><li>switch后面是一个表达式（即：常量值、变量、一个有返回值的函数）</li><li>case后面的值如果是常量值（字面量）。则要求不能重复</li><li>case后面的各个值的数据类型，必须和switch的表达式数据类型一致。</li><li>case后面带多个值，使用逗号间隔。case 值1,值2,....</li><li>case后面不需要break</li><li>default语句不是必须，位置也是随意的。</li><li>switch后面可以不带表达式，当做if分支来使用</li></ul><pre><code class="language-go">switch{    case a == 1:        fmt.Println(&quot;aaa&quot;)    case a == 2:        fmt.Println(&quot;bbb&quot;)}</code></pre><ul><li>switch后也可以直接声明/定义一个变量，分号结束</li><li>switch穿透，利用<code>fallthrough</code>关键字，如果在case语句块后增加<code>fallthrough</code>，则会执行下一个case，也叫switch穿透。</li></ul><h3 id="循环结构">循环结构</h3><h4 id="语法结构">语法结构</h4><pre><code class="language-go">for 初始表达式;布尔表达式;迭代因子 {    循环体;}</code></pre><h4 id="注意事项-1">注意事项</h4><ul><li>for的初始表达式，不能使用<code>var a int = 10</code>，可使用<code>:=</code></li><li>格式灵活</li></ul><pre><code class="language-go">    i := 1    for i &lt;= 5 {        fmt.Println(&quot;你好，Golang&quot;)        i++    }</code></pre><ul><li>死循环</li></ul><pre><code class="language-go">    for{        fmt.Println(&quot;你好，Golang&quot;)        i++    }    for ;;{        fmt.Println(&quot;你好，Golang&quot;)        i++    }</code></pre><h4 id="for-range">for range</h4><ul><li>for range结构是Go语言特有的一种迭代结构。在许多情况下都非常有用，for range可以遍历数组、切片、字符串、map及通道，for range 语法上类似于其他语言中的foreach余元。一般形式为：</li></ul><pre><code class="language-go">for key,val := range coll{    ...}</code></pre><ul><li></li></ul><pre><code class="language-go">    //方式一：普通for循环：按照字节进行遍历输出（暂不用中文）    var str string = &quot;helllo golang&quot;    for i := 0; i &lt; len(str); i++ {        fmt.Printf(&quot;%c\n&quot;, str[i])    }    //方式二：for range支持中文    for i , value := range str{        fmt.Printf(&quot;索引为:%d,具体的值为：%c \n&quot;,i,value)    }    //对str进行遍历，遍历的每个结果的索引值被i接收，每个结果的具体数值被value接收    //遍历对字符进行遍历</code></pre><h3 id="关键字">关键字</h3><h4 id="关键字-break">关键字 break</h4><ul><li>switch分支中，每个case分支后都用break结束当前分支，但是在go语言中<code>break</code>可省略不写</li><li><code>break</code>可以结束正在执行的循环</li><li><code>break</code>的作用是离它最近的循环</li><li>标签的使用效果</li></ul><pre><code class="language-go">label1:for i:=1;i&lt;=5;i++ {for j:=2;j&lt;=4;j++ {fmt.Printf(&quot;i: %v,j:%v\n&quot;,i, j)if i==2&amp;&amp; j== 2 {break label1}}}</code></pre><p>注意：如果标签没使用的话则不用定义。</p><h4 id="关键字-continue">关键字 continue</h4><pre><code class="language-go">for i:=1; i&lt;= 100;i++ {if i % 6 != 0 {continue  //结束本次循环，继续下一个循环}fmt.Println(i)}</code></pre><ul><li>continue的作用就是结束离它进的那个循环，继续离他近的那个循环</li><li>标签也可以同样在continue中使用</li></ul><pre><code class="language-go">label1:for i:=1;i&lt;=5;i++ {for j:=2;j&lt;=4;j++ {if i==2 &amp;&amp; j== 2 {continue label1}                fmt.Printf(&quot;i: %v,j:%v\n&quot;,i, j)}}</code></pre><h4 id="关键字-goto">关键字 goto</h4><ul><li>提供语法，但不建议使用</li><li>一般都配合条件结构一起使用</li></ul><pre><code class="language-go">fmt.Println(&quot;hello golang1&quot;)fmt.Println(&quot;hello golang2&quot;)if 1 == 1 {goto label1}fmt.Println(&quot;hello golang3&quot;)fmt.Println(&quot;hello golang4&quot;)fmt.Println(&quot;hello golang5&quot;)fmt.Println(&quot;hello golang6&quot;)fmt.Println(&quot;hello golang7&quot;)label1:fmt.Println(&quot;hello golang8&quot;)fmt.Println(&quot;hello golang9&quot;)</code></pre><h4 id="关键字-return">关键字 return</h4><ul><li>在方法和函数中使用较多</li><li>用于结束当前函数</li></ul><pre><code class="language-go">for i := 1; i &lt;= 100 ; i++ {fmt.Println(i)if i == 14 {return  // 结束当前的函数，下面的hello golang不执行}}fmt.Printf(&quot;hello golang&quot;)</code></pre>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[IDEA使用技巧（一）]]></title>
                <link rel="alternate" type="text/html" href="http://www.zuxyu.com/archives/idealearningproject学习笔记" />
                <id>tag:http://www.zuxyu.com,2021-08-17:idealearningproject学习笔记</id>
                <published>2021-08-17T16:20:17+08:00</published>
                <updated>2021-08-17T21:13:49+08:00</updated>
                <author>
                    <name>骑头猪逛街</name>
                    <uri>http://www.zuxyu.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<h1 id="idea的idealearningproject中的学习技巧">IDEA的IdeaLearningProject中的学习技巧</h1><h2 id="1上下文操作">1、上下文操作</h2><ol><li>当代码块中的入参并未在函数中引用时，可将光标移动到灰色代码使用快捷键<code>⌥</code>+<code>↩</code>弹出建议。快捷去除不要的部分。<br /><img src="/upload/2021/08/QQ20210817-164520@2x-4a8aa91596c445be82d14ad71b1cbbaf.png" alt="QQ202108171645202x.png" /></li><li>在具体方法中可以使用建议，使用同样快捷键，可优化代码。<br />修改前</li></ol><pre><code class="language-java">    public int intentionExample(boolean z, boolean a, boolean b) {        if (!(z ? a : b)) return 1;        return 2;    }</code></pre><p>修改后</p><pre><code class="language-java">    public int intentionExample(boolean z, boolean a, boolean b) {        if (z ? !a : !b) return 1;        return 2;    }</code></pre><h2 id="2-全局搜索">2. 全局搜索</h2><p>1.<code>⌘</code>+<code>⇧</code>+<code>A</code> 弹出全局搜索</p>]]>
                </content>
            </entry>
            <entry>
                <title><![CDATA[Go语言笔记（一）]]></title>
                <link rel="alternate" type="text/html" href="http://www.zuxyu.com/archives/go语言笔记一" />
                <id>tag:http://www.zuxyu.com,2021-08-16:go语言笔记一</id>
                <published>2021-08-16T22:56:40+08:00</published>
                <updated>2021-08-18T23:36:23+08:00</updated>
                <author>
                    <name>骑头猪逛街</name>
                    <uri>http://www.zuxyu.com</uri>
                </author>
                <content type="html">
                        <![CDATA[<h1 id="前言">前言</h1><p>文章假设用户已经掌握一门编程语言，如Java，C。</p><h1 id="变量">变量</h1><ul><li>全局变量：定义在函数外的变量</li><li>局部变量：定义在{}中的变量</li><li>Go的变量由字母、数字、下划线组成，其中首个字符不能为数字</li><li>变量申明一般为var关键字，且为强类型变量。</li><li>变量首字母的大小写来确定访问的权限。无论是方法名、常量、变量名还是结构体的名称，如果首字母大写，则可以被其他的包访问；如果首字母小写，则只能在本包中使用</li></ul><h2 id="变量的使用步骤">变量的使用步骤</h2><pre><code class="language-go">package mainimport &quot;fmt&quot;func main(){    // 1.变量的声明    var age int    // 2.变量的赋值    age = 18    // 3.变量的使用    fmt.Println(&quot;age=&quot;,age)    // 4.设声明和赋值可合成一句    var age int = 19    // 5.不可以在赋值的时候给不匹配的类型    var num int = 12.54   // 这种方式就是错误的}</code></pre><h2 id="变量的4种使用方式">变量的4种使用方式</h2><pre><code class="language-go">package mainimport &quot;fmt&quot;func main(){    // 第一种：变量的使用方式    var num int = 18    fmt.Println(num)    // 第二种：指定变量的类型，但不是赋值，使用默认值    var num2 int    fmt.Println(num2)    // 第三种：如果没有写变量的类型，会根据等号后面的值进行判定变量的类型。（自动类型推断)    var num3 = 10  // var num3 = 10.23 var num3 = &quot;10.23&quot;    fmt.Println(num3)    // 第四种：省略var,注意:=,不能写为=    sex := &quot;男&quot;}</code></pre><h2 id="一次可声明多个变量">一次可声明多个变量</h2><pre><code class="language-go">package mainimport &quot;fmt&quot;var n7 = 100var n8 = 9.7// 设计者认为上面的全局变量写法太麻烦。可以一次性声明var {    n9 = 500    n10 = &quot;Jack&quot;}func main(){    var n1,n2,n3 int    fmt.Println(n1)    fmt.Println(n2)    fmt.Println(n3)    var n4,name,n5 = 10,&quot;Tom&quot;,7.8    fmt.Println(n4)    fmt.Println(name)    fmt.Println(n5)    n6,height := 6.9,123.6    fmt.Println(n6)    fmt.Println(height)    fmt.Println(n7)    fmt.Println(n8)    fmt.Println(n9)    fmt.Println(n10)}</code></pre><h1 id="数据类型">数据类型</h1><p>Go中的数据类型分为<code>基本数据类型</code>和<code>派生数据类型</code></p><h2 id="基本数据类型">基本数据类型</h2><ol><li>数值型<ul><li>整数类型（<code>int</code>,<code>int8</code>,<code>int16</code>,<code>int32</code>,<code>int64</code>,<code>uint</code>,<code>uint8</code>,<code>uint16</code>,<code>uint32</code>,<code>uint64</code>,<code>byte</code>）</li><li>浮点类型</li></ul></li><li>字符型<br />没有单独的字符类型，使用<code>byte</code>来保存单个字母字符</li><li>布尔型（bool)</li><li>字符串(string)</li></ol><h2 id="派生数据类型或复杂数据类型">派生数据类型或复杂数据类型</h2><p>1.指针<br />2.数组<br />3.结构体<br />4.管道<br />5.函数<br />6.切片<br />7.接口<br />8.map</p><h1 id="指针">指针</h1><p><code>&amp;</code>:获取内存地址<br /><code>*</code>:取内存地址的值<br />1.可以通过指针改变指向值<br />2.指针变量接收的一定是地址值<br />3.指针变量的地址不可以不匹配<br />4.基本数据类型都有对应的指针类型，形式为*数据类型，如int，*int</p><pre><code class="language-go">package mainimport &quot;fmt&quot;func main(){    var age int = 18    //&amp;符号+变量就可以获取这个变量内存的地址    fmt.Println(&amp;age)       // 定义一个指针变量    // var代表要声明一个变量    // ptr 指针变量的名字    // ptr对应的类型是：*int 是一个指针类型（可以理解为 指向int类型的指针）    var ptr *int = &amp;age    fmt.Println(ptr)    fmt.Println(&quot;ptr本身存储空间的地址为：&quot;,&amp;ptr)    //获取ptr这个指针指向的数据    fmt.Printf(&quot;ptr指向的数值为%v&quot;, *ptr)    var num int = 10    fmt.Println(num)    var ptr *int = &amp;num    *ptr = 20    fmt.Println(num)  // 这时候发现值发生了改变    }</code></pre><h1 id="关键字">关键字</h1><p>Go语言中一共有25个关键字</p><table><thead><tr><th>break</th><th>default</th><th>func</th><th>interface</th><th>select</th></tr></thead><tbody><tr><td>case</td><td>defer</td><td>go</td><td>map</td><td>struct</td></tr><tr><td>chan</td><td>else</td><td>goto</td><td>package</td><td>switch</td></tr><tr><td>const</td><td>fallthrough</td><td>if</td><td>range</td><td>type</td></tr><tr><td>continue</td><td>for</td><td>import</td><td>return</td><td>var</td></tr></tbody></table><p>预定义标识符：一共有36个</p><table><thead><tr><th>append</th><th>bool</th><th>byte</th><th>cap</th><th>close</th><th>complex</th></tr></thead><tbody><tr><td>complex64</td><td>complex128</td><td>uint16</td><td>copy</td><td>false</td><td>float32</td></tr><tr><td>float64</td><td>imag</td><td>int</td><td>int8</td><td>in16</td><td>uint32</td></tr><tr><td>int32</td><td>int64</td><td>lota</td><td>len</td><td>make</td><td>new</td></tr><tr><td>nil</td><td>panic</td><td>uint64</td><td>print</td><td>println</td><td>real</td></tr><tr><td>recover</td><td>string</td><td>true</td><td>uint</td><td>uint8</td><td>uintprt</td></tr></tbody></table><h1 id="运算符">运算符</h1><h2 id="1-算数运算符">1. 算数运算符</h2><p><code>+</code>  代表正数、相加操作、字符串拼接</p><pre><code class="language-go">var n1 int = +10var n2 int = 4 + 7var n3 string = &quot;abc&quot; + &quot;def&quot;</code></pre><p><code>/</code>  两个int类型数据计算结果已定位整数类型，浮点类型运算结果为浮点类型</p><pre><code class="language-go">fmt.Println(10/3)fmt.Println(10.0/3)</code></pre><p><code>%</code>取余，等价公式：a%b = a-a/b*b</p><pre><code class="language-go">fmt.Println(10%3)   ====&gt; 10-10/3*3  10/3为int类型，因此得值为3，10-3*3=1fmt.Println(-10%3)fmt.Println(10%-3)fmt.Println(-10%-3)</code></pre><p><code>++</code>  自增，+1操作</p><pre><code class="language-go">var a int  = 10a++</code></pre><p><code>--</code>  自减 同自增，-1操作<br />在go语言里，++和--操作简单，与Java不一样，只能单独使用，不能参与运算中。且只能写在变量后面，不能写在变量前面。</p><pre><code class="language-go">--a 这是错误的写法。</code></pre><h2 id="2-赋值运算符">2. 赋值运算符</h2><p>赋值运算符指的是：<code>=</code>,<code>+=</code>,<code>-=</code>,<code>*=</code>,<code>/=</code>,<code>%=</code></p><h2 id="3-关系运算符">3. 关系运算符</h2><p>关系运算符指的是：<code>==</code>,<code>!=</code>,<code>&gt;</code>,<code>&lt;</code>,<code>&gt;=</code>,<code>&lt;=</code><br />他们的返回结果都是bool类型。</p><h2 id="4-逻辑运算符">4. 逻辑运算符</h2><p>与: <code>&amp;&amp;</code><br />或: <code>||</code><br />非: <code>!</code></p><h2 id="5-位运算符">5. 位运算符</h2><p>位运算符指的是：<code>&amp;</code>,<code>|</code>,<code>^</code>,<code>&gt;&gt;</code>,<code>&lt;&lt;</code><br />是对整数的二进制进行的运算。</p><pre><code>A = 0010 1000B = 0001 1101-----------------A&amp;B = 0000 1000A|B = 0011 1101A^B = 0011 0101A&lt;&lt;2 = 1010 0000A&gt;&gt;2 = 0000 1010</code></pre><h2 id="6-其他运算符">6. 其他运算符</h2><p><code>&amp;</code>：返回变量的存储地址<br /><code>*</code>：取指针变量对应的数值</p><h2 id="7-运算符优先级">7. 运算符优先级</h2><table><thead><tr><th>优先级</th><th>分类</th><th>运算符</th><th>结合性</th></tr></thead><tbody><tr><td>1</td><td>逗号运算符</td><td>,</td><td>从左到右</td></tr><tr><td>2</td><td>赋值运算符</td><td>=,+=,-=,*=,/=,%=,&gt;&gt;=,&lt;&lt;=,&amp;=,^=,|=</td><td><font color=red>从右到左</font></td></tr><tr><td>3</td><td>逻辑或</td><td>||</td><td>从左到右</td></tr><tr><td>4</td><td>逻辑与</td><td>&amp;&amp;</td><td>从左到右</td></tr><tr><td>5</td><td>按位或</td><td>|</td><td>从左到右</td></tr><tr><td>6</td><td>按位异或</td><td>^</td><td>从左到右</td></tr><tr><td>7</td><td>按位与</td><td>&amp;</td><td>从左到右</td></tr><tr><td>8</td><td>相等/不等</td><td>==,!=</td><td>从左到右</td></tr><tr><td>9</td><td>关系运算符</td><td>&lt;,&lt;=,&gt;,&gt;=</td><td>从左到右</td></tr><tr><td>10</td><td>位移运算符</td><td>&lt;&lt;,&gt;&gt;</td><td>从左到右</td></tr><tr><td>11</td><td>加法/减法</td><td>+,-</td><td>从左到右</td></tr><tr><td>12</td><td>乘法/除法/取余</td><td>*(乘号),/,%</td><td>从左到右</td></tr><tr><td>13</td><td>单目运算符</td><td>!,*(指针),&amp;,++,--,+(正号),-(负号)</td><td><font color=red>从右到左</font></td></tr><tr><td>14</td><td>后缀运算符</td><td>(),[],-&gt;</td><td>从左到右</td></tr></tbody></table><p>为了提高优先级，可以直接加括号</p><h2 id="8-获取用户终端输入">8. 获取用户终端输入</h2><p>录入数据的类型一定要匹配。底层会判定类型<br />方式一：</p><pre><code class="language-go">package mainimport &quot;fmt&quot;func main(){//实现功能：键盘录入学生的年龄、姓名、成绩，是否是VIP//方式1：Scanlnvar age intfmt.Println(&quot;请录入学生的年龄：&quot;)//传入age的地址的目的：在Scanln函数中，对地址的值进行改变的时候，实际外面的age也被影响了。fmt.Scanln(&amp;age)var name stringfmt.Println(&quot;请录入学生的姓名：&quot;)fmt.Scanln(&amp;name)var score float32fmt.Println(&quot;请录入学生的成绩：&quot;)fmt.Scanln(&amp;score)var isVIP boolfmt.Println(&quot;请录入学生是否为VIP：&quot;)fmt.Scanln(&amp;isVIP)//将上述数据在控制台打印输出：fmt.Printf(&quot;学生的年龄为：%v,姓名为：%v，成绩为：%v，是否为VIP：%v&quot;,age,name,score,isVIP)}</code></pre><p>方式二：</p><pre><code class="language-go">package mainimport &quot;fmt&quot;func main() {//实现功能：键盘录入学生的年龄、姓名、成绩，是否是VIP//方式1：Scanlnvar age intvar name intvar score float32var isVIP boolfmt.Println(&quot;学生的年龄 姓名 成绩 是否为VIP&quot;)fmt.Scanf(&quot;%d %s %f %t&quot;, &amp;age, &amp;name, &amp;score, &amp;isVIP)}</code></pre>]]>
                </content>
            </entry>
</feed>
