囲碁の基本 2

目次

オペレーター

算術演算子

関係演算子

論理演算子

ビット演算子

代入演算子

プロセス制御

もし判断なら

判定の場合の特殊な書き方

for ループ

無限ループ

範囲ループ用

練習

休憩と継続

スイッチケース

goto (指定したラベルにジャンプ)

(配列) 配列

配列定義

配列の初期化

配列トラバーサル

多次元配列

多次元配列の走査

配列は値型です

練習

(無言) スライス

スライスを宣言する

make 関数はスライスを作成します

スライスの性質

スライスは直接比較できません

スライスのカット

スライストラバーサル

スライス展開 (追加)

コピー機能

スライスから要素を削除

練習

ポインター

新しく作る

新しい

作る

新品とメーカーの違い


オペレーター

演算子は、プログラムの実行中に数学演算または論理演算を実行するために使用されます。

Go 言語の組み込み演算子は次のとおりです。

  1. 算術演算子

  2. 関係演算子

  3. 論理演算子

  4. ビット演算子

  5. 代入演算子

算術演算子

オペレーター 説明
+ 加算する
- 減算
* 掛けた
/ 分割する
% 余剰

注: ++ (increment) と--(decrement) は Go 言語の個別のステートメントであり、演算子ではありません。

package main

import "fmt"

func main() {
	a := 10
	b := 20

	fmt.Println(a + b)
	fmt.Println(a - b)
	fmt.Println(a * b)
	fmt.Println(a / b)
	fmt.Println(a % b)
}

30
-10
200
0
10

関係演算子

オペレーター 説明
== 2 つの値が等しいかどうかをチェックし、等しい場合は True を返し、そうでない場合は False を返します。
!= 2 つの値が等しくないかどうかを確認し、等しくない場合は True、そうでない場合は False を返します。
> 左側の値が右側の値より大きいかどうかを確認し、大きい場合は True を返し、そうでない場合は False を返します。
>= 左側の値が右側の値以上かどうかを確認し、そうであれば True を返し、そうでなければ False を返します。
< 左の値が右の値より小さいかどうかをチェックし、そうであれば True を返し、そうでなければ False を返します。
<= 左側の値が右側の値以下かどうかを確認し、そうであれば True を返し、そうでなければ False を返します。
package main

import "fmt"

func main() {
	a := 10
	b := 20
	fmt.Println(a == b) // false
	fmt.Println(a <= b) // true
	fmt.Println(a >= b) // false
	fmt.Println(a != b) // true
	fmt.Println(a > b)  // false
	fmt.Println(a < b)  // true
}

false
true
false
true
false
true

論理演算子

オペレーター 説明
&& 論理および演算子。両方のオペランドが True の場合は True、それ以外の場合は False。
|| 論理または演算子。両方のオペランドが True の場合は True、それ以外の場合は False。
! 論理否定演算子。条件が True の場合は False、それ以外の場合は True です。
package main

import "fmt"

func main() {
	a := 10
	b := 20

	fmt.Println(a < b && a == b) // false
	fmt.Println(a < b || a == b) // true
	fmt.Println(!(a > b))        // true
}

false
true
true

ビット演算子

オペレーター 説明
& 演算に含まれる対応する 2 つの数値のバイナリ フェーズ AND。(どちらも 1 で 1 になる)
| | 演算に含まれる 2 つの数値に対応するバイナリ フェーズ OR。(2 つのビットのいずれかが 1 の場合は 1)
^ 演算に関与する 2 つの数値の対応する 2 進ビットが異なるか、対応する 2 つの 2 進ビットが異なる場合、結果は 1 になります。(2 つのビットが異なる場合は 1)
<< n ビット左にシフトすることは、2 を n 乗することです。「a<<b」は、a のすべてのバイナリ ビットを左に b ビットだけシフトし、上位ビットを破棄し、下位ビットを 0 で埋めます。
>> n ビット右にシフトすることは、2 を n 乗することです。「a>>b」は、a のすべてのバイナリ ビットを b ビットだけ右にシフトすることです。
package main

import "fmt"

func main() {
	a := 2 // 010
	b := 3 // 011

	fmt.Println(a & b) // 010 --> 2(上下对应位置都是1就是1)
	fmt.Println(a | b) // 011 --> 3(上下对应位置只要有一个1就是1)
	fmt.Println(a ^ b) // 001 --> 1(上下对应位置只要不相等就是1)

	fmt.Println(a << b) // a*2^b --> 2*2^3 --> 16
	fmt.Println(a >> b) // a/2^b --> 2/2^3 --> 0.25
}

2
3
1
16
0

代入演算子

オペレーター 説明
= 式の値を左辺値に代入する単純な代入演算子
+= 追加してから割り当てる
-= 減算してから代入
*= 乗算して代入
/= 分割後に割り当てる
%= 残りの後に割り当てる
<<= 左シフト後の代入
>>= 右シフト後の代入
&= ビット単位および事後代入
|= ビット単位または事後代入
^= ビットごとの XOR 後の代入
package main

import "fmt"

func main() {
	var a1 int
	a1 = 5 // 赋值运算符
	fmt.Println(a1)

	a1++ // a1+1
	fmt.Println(a1)

	a1-- // a1-1
	fmt.Println(a1)

	a1 += 5 // 相加之后再赋值
	fmt.Println(a1)

	a1 -= 3 // 相减之后再赋值
	fmt.Println(a1)

	a1 *= 2 // 相乘后再赋值
	fmt.Println(a1)

	a1 /= 3 // 相除后再赋值
	fmt.Println(a1)

	a1 %= 3 // 求余后再赋值
	fmt.Println(a1)
}

5
6
5
10
7
14
4
1

プロセス制御

フロー制御は, 論理の方向と実行順序を制御するための各プログラミング言語の重要な部分です. Go 言語で最も一般的に使用されるフロー制御は合計であり, 合計は主にコードを簡素化し繰り返しコードを減らすために作成された構造です.属しifます.フロー制御の拡張クラス。forswitchgoto

もし判断なら

if 表达式1 {
    分支1
} else if 表达式2 {
    分支2
} else{
    分支3
}
package main

import "fmt"

func main() {
	age := 19
	if age > 18 {
		fmt.Println("你已经成年了!")
	} else {
		fmt.Println("你还没有成年!")
	}

	if age > 35 {
		fmt.Println("人到中年了")
	} else if age > 18 {
		fmt.Println("年轻就是好")
	} else {
		fmt.Println("好好学习,天天上当")
	}
}

你已经成年了!
年轻就是好

Go 言語では、if一致する左括弧をand と同じ行に配置する{ 必要があると規定されています。そうしないと、コンパイル エラーが発生します。同様に、一致もand と同じ行に記述する必要があり、前または右の中括弧と同じ行に記述する必要があります。if和表达式{ else{ elseelseifelse if

判定の場合の特殊な書き方

if 条件判定の書き方も特殊で、if 式の前に実行文を追加して、変数の値で判定するという方法もあります。

func ifDemo2() {
	if score := 65; score >= 90 {
		fmt.Println("A") 
	} else if score > 75 {
		fmt.Println("B")
	} else {
		fmt.Println("C")
	}
}

for ループ

Go 言語のすべてのループ タイプは、forキーワードを使用して実行できます。

for ループの基本的な形式は次のとおりです。

for 初始语句;条件表达式;结束语句{
    循环体语句
}

条件式が返されると、true条件式が返されてfalse自動的にループを終了するまで、ループ本体が継続的にループします。

package main

import "fmt"

func main() {
	for i := 0; i <= 10; i++ {
		fmt.Println(i)
	}
}

0
1
2
3
4
5
6
7
8
9
10

for ループの最初のステートメントは無視できますが、最初のステートメントの後のセミコロンは次のように記述する必要があります。

package main

import "fmt"

func main() {
	num1 := 5
	for ; num1 <= 10; num1++ {
		fmt.Println(num1)
	}
}

5
6
7
8
9

for循环的初始语句和结束语句都可以省略,例如:

package main

import "fmt"

func main() {

	/*num1 := 5
	for ; num1 < 10; num1++ {
		fmt.Println(num1)
	} */

	num1 := 5
	for num1 < 10 {
		fmt.Println(num1)
		num1++
	}

}

5
6
7
8
9

这种写法类似于其他编程语言中的while,在while后添加一个条件表达式,满足条件表达式时持续循环,否则结束循环。

死循环

注意:Go语言性能比较优异,切记不可操作此循环(了解即可),否则可能导致电脑卡死或蓝屏。

for {
    循环体语句
}

for循环可以通过breakgotoreturnpanic语句强制退出循环。

for range 循环

Go语言中可以使用for range遍历数组、切片、字符串、map 及通道(channel)。 通过for range遍历的返回值有以下规律:

  1. 数组、切片、字符串返回索引和值。

  2. map返回键和值。

  3. 通道(channel)只返回通道内的值。

package main

import "fmt"

func main() {
	name := "Hello Go语言"
	for index, value := range name {
		fmt.Printf("%d-%c\n", index, value)
	}
}

0-H
1-e
2-l
3-l
4-o
5- 
6-G
7-o
8-语
11-言

练习

  1. 九九乘法表
package main

import "fmt"

func main() {
	for i := 1; i <= 9; i++ {
		for j := 1; j <= i; j++ {
			fmt.Printf("%d*%d=%d\t", j, i, i*j)
		}
		fmt.Printf("\n")
	}
}

1*1=1	
1*2=2	2*2=4	
1*3=3	2*3=6	3*3=9	
1*4=4	2*4=8	3*4=12	4*4=16	
1*5=5	2*5=10	3*5=15	4*5=20	5*5=25	
1*6=6	2*6=12	3*6=18	4*6=24	5*6=30	6*6=36	
1*7=7	2*7=14	3*7=21	4*7=28	5*7=35	6*7=42	7*7=49	
1*8=8	2*8=16	3*8=24	4*8=32	5*8=40	6*8=48	7*8=56	8*8=64	
1*9=9	2*9=18	3*9=27	4*9=36	5*9=45	6*9=54	7*9=63	8*9=72	9*9=81	

break和continue

break为结束循环,continue为跳过本次循环继续执行下一次循环。

package main

import "fmt"

func main() {

	// 当i=5时结束当前循环
	/* for i := 0; i <= 10; i++ {
		if i == 5 {
			break
		} else {
			fmt.Println(i)
		}
	}
	fmt.Println("Over!!!") */

	// 当i=5时跳过本次循环
	for i := 0; i <= 10; i++ {
		if i == 5 {
			continue
		} else {
			fmt.Println(i)
		}
	}
	fmt.Println("Over!!!")
}

0
1
2
3
4
6
7
8
9
10
Over!!!

switch case

使用switch语句可方便地对大量的值进行条件判断。

package main

import "fmt"

func main() {
	num1 := 3
	switch num1 {
	case 1:
		fmt.Println("张三")
	case 2:
		fmt.Println("李四")
	case 3:
		fmt.Println("王五")
	case 4:
		fmt.Println("赵六")
	case 5:
		fmt.Println("小七")
	default:
		fmt.Println("无效输入!!!")
	}
}

王五

一个分支可以有多个值,多个case值中间使用英文逗号分隔。

package main

import "fmt"

func main() {
	switch num2 := 3; num2 {
	case 1, 3, 5, 7, 9:
		fmt.Println("这是奇数")
	case 2, 4, 6, 8, 10:
		fmt.Println("这是偶数")
	default:
		fmt.Println(num2)
	}
}

这是奇数

分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量。例如:

package main

import "fmt"

func main() {
	age := -3
	switch {
	case age <= 18 && age > 0:
		fmt.Println("好好学习吧")
	case age <= 35 && age > 18:
		fmt.Println("好好赚钱奥")
	case age > 35:
		fmt.Println("还是身体重要!!!")
	default:
		fmt.Println("无效的输入")
	}
}

无效的输入

goto(跳转到指定的标签)

goto语句通过标签进行代码间的无条件跳转。goto语句可以在快速跳出循环、避免重复退出上有一定的帮助。Go语言中使用goto语句能简化一些代码的实现过程。 例如双层嵌套的for循环要退出时:

package main

import "fmt"

func main() {
	var breakTag bool  // 初始化标志
	for i := 0; i < 10; i++ {
		for j := 0; j <= i; j++ {
			if j == 5 {
				breakTag = true
			} else {
				fmt.Println(i, j)
			}
		}
		if breakTag {
			break
		}
	}
}

使用goto语句能简化代码:

package main

import "fmt"

func main() {
	for i := 0; i <= 10; i++ {
		for j := 1; j <= i; j++ {
			if j == 5 {
				goto breakTag // 设置结束标志
			}
			fmt.Print(j)
		}
		fmt.Print("\n")
	}
	// 结束
breakTag:
	fmt.Println("循环已经结束")
}

1
12
123
1234
1234循环已经结束

(Array)数组

数组是同一种数据类型元素的集合。 在Go语言中,数组从声明时就确定,使用时可以修改数组成员,但是数组大小不可变化。基本语法如下:

package main

import "fmt"

func main() {
	var arr1 [3]bool
	fmt.Printf("%T\n", arr1)
	fmt.Println(arr1)
}

[3]bool
[false false false]

注意:Go语言中数组的长度就是数组类型的一部分!!!

数组定义

var 数组的名字 [数组的数量]数组的类型

var arr [4]int

比如:var arr1 [5]int, 数组的长度必须是常量,并且长度是数组类型的一部分。一旦定义,长度不能变。 [5]int[10]int是不同的类型。

数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1,访问越界(下标在合法范围之外),则触发访问越界,会报错。

package main

import "fmt"

func main() {
	var arr1 [3]bool
	fmt.Println(arr1[5])
}

# command-line-arguments
day3\数组.go:7:19: invalid argument: array index 5 out of bounds [0:3]

数组的初始化

如果不初始化,默认的元素都是零值(布尔值:false;整型和浮点型:0;字符串:"")。

方式1:

package main

import "fmt"

var name = [3]string{"老王", "胖子", "大胖子"}

func main() {
    fmt.Println(name)
    
    arr1 := [3]bool{true, true, false}
	fmt.Println(arr1)
}

[老王 胖子 大胖子]
[true true false]

方式2:

根据初始值的个数自行推断数组的长度,例如:

package main

import "fmt"

func main() {
	// 方式1
    /* arr1 := [3]bool{true, true, false}
	fmt.Println(arr1) */

	// 方式2
    arr2 := [...]string{"hpl", "xxx", "aaa", "laowang"}
	fmt.Println(arr2)
}

[hpl xxx aaa laowang]

方式3:

使用指定索引值的方式来初始化数组,例如:

package main

import "fmt"

func main() {
	// 方式1
    /* arr1 := [3]bool{true, true, false}
	fmt.Println(arr1) */

	// 方式2
    /* arr2 := [...]string{"hpl", "xxx", "aaa", "laowang"}
	fmt.Println(arr2) */

	// 方式3
    arr3 := [5]int{1: 2, 4: 666}
	fmt.Println(arr3)
}

[0 2 0 0 666]

数组的遍历

数组的遍历有两种方式:

package main

import "fmt"

func main() {
    address := [...]string{"西安", "北京", "汉中", "洛阳"}

	// 方式1
	for i := 0; i < len(address); i++ {
		fmt.Println(address[i])
	}

	fmt.Println("---------------------")

	// 方式2
	for index, value := range address {
		fmt.Println(index, value)
	}
}

西安
北京
汉中
洛阳
---------------------
0 西安
1 北京
2 汉中
3 洛阳

多维数组

Go语言是支持多维数组的,我们这里以二维数组为例(数组中又嵌套数组)。

package main

import "fmt"

func main() {
	// 多维数组
    arr1 := [...][3]int{
   
   {1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
	fmt.Println(arr1)

}

[[1 2 3] [4 5 6] [7 8 9]]

多维数组的遍历

package main

import "fmt"

func main() {
	// 多维数组
    arr1 := [...][3]int{
   
   {1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
	// fmt.Println(arr1)

	// 二维数组的遍历
	for i := 0; i < len(arr1); i++ {
		for j := 0; j < len(arr1[i]); j++ {
			fmt.Printf("%d ", arr1[i][j])
		}
		fmt.Print("\n")
	}

}

1 2 3 
4 5 6 
7 8 9 

注意: 多维数组只有第一层可以使用[...]来让编译器推导数组长度。例如:

//支持的写法
arr1 := [...][2]string{
	{"北京", "上海"},
	{"广州", "深圳"},
	{"成都", "重庆"},
}
//不支持多维数组的内层使用[...]
arr2 := [3][...]string{
	{"北京", "上海"},
	{"广州", "深圳"},
	{"成都", "重庆"},
}

数组是值类型

数组是值类型,赋值和传参会复制整个数组。因此改变副本的值,不会改变本身的值。

package main

import "fmt"

func main() {
	arr4 := [...]int{2, 5, 8}
	arr5 := arr4
	arr5[1] = 666
	fmt.Println(arr4, arr5)
	fmt.Println(arr4 == arr5)
	fmt.Println(arr4 != arr5)

}

[2 5 8] [2 666 8]
false
true

练习

1.求数组[1, 3, 5, 7, 8]所有元素的和

package main

import "fmt"

func main() {
	arr1 := [...]int{1, 3, 5, 7, 8}
	var count int
	for _, value := range arr1 {
		count += value
	}
	fmt.Println("数组arr1的元素之和为:", count)
}

数组arr1的元素之和为: 24

2.找出数组中和为指定值的两个元素的下标,比如从数组[1, 3, 5, 7, 8]中找出和为8的两个元素的下标分别为(0,3)和(1,2)。

package main

import "fmt"

func main() {
	arr1 := [...]int{1, 3, 5, 7, 8}
		for i, v := range arr1 {
		for j := i + 1; j < len(arr1); j++ {
			if v+arr1[j] == 8 {
				fmt.Printf("(%d %d)\n", i, j)
			}
		}
	}
}

(0 3)
(1 2)

(silce)切片

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。

切片是一个引用类型,它的内部结构包含地址长度容量。切片一般用于快速地操作一块数据集合。

声明切片

package main

func main() {
	var s []int
}
package main

import "fmt"

func main() {
	s1 := []int{1, 3, 5}
	s2 := []string{"西安", "北京", "上海"}
	fmt.Println(s1, s2)
	fmt.Println(s1 == nil) // nil表示空的意思
}

[1 3 5] [西安 北京 上海]
false

切片拥有自己的长度容量,我们可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量。

容量:切片的容量就是底层数组第一个元素到最后一个元素。

package main

import "fmt"

func main() {
	// 切片的长度和容量
	s3 := []string{"西安", "北京", "上海"}
	fmt.Println("切片的长度是:", len(s3), "切片的容量是:", cap(s3))
}

切片的长度是: 3 切片的容量是: 3
package main

import "fmt"

func main() {
	arr1 := []int{1, 5, 7, 8, 9, 30, 50, 77, 666}
	s1 := arr1[1:4]
	s2 := arr1[:3]
	s3 := arr1[3:]
	s4 := arr1[:]
	arr1[3] = 999
	fmt.Println(s1, len(s1), cap(s1))
	fmt.Println(s2, len(s2), cap(s2))
	fmt.Println(s3, len(s3), cap(s3))
	fmt.Println(s4, len(s4), cap(s4))
}

[5 7 999] 3 8
[1 5 7] 3 9
[999 9 30 50 77 666] 6 6
[1 5 7 999 9 30 50 77 666] 9 9

make函数创建切片

我们上面都是基于数组来创建的切片,如果需要动态的创建一个切片,我们就需要使用内置的make()函数,格式如下:

make([]T, size, cap)
  • T:切片的元素类型

  • size:切片中元素的数量

  • cap:切片的容量

package main

import "fmt"

func main() {
	// 使用make函数创建切片
	s1 := make([]int, 5, 10) // 类型、长度、容量(容量若不写,默认等于长度的值)
	fmt.Println(s1, len(s1), cap(s1))
}

[0 0 0 0 0] 5 10

上面代码中s1的内部存储空间已经分配了10个,但实际上只用了5个。 容量并不会影响当前元素的个数,所以len(s1)返回5,cap(s1)则返回该切片的容量10。

切片的本质

切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)

切片不能直接比较

切片之间是不能比较的,我们不能使用==操作符来判断两个切片是否含有全部相等元素。 切片唯一合法的比较操作是和nil比较。 一个nil值的切片并没有底层数组,一个nil值的切片的长度和容量都是0。但是我们不能说一个长度和容量都是0的切片一定是nil

package main

import "fmt"

func main() {
    var s1 []int
	s2 := make([]int, 0, 0)
	fmt.Println(s2, len(s2), cap(s2))
	fmt.Println(s1 == nil, s2 == nil)
}

[] 0 0
true false

所以要判断一个切片是否是空的,要是用len(s2) == 0来判断,不应该使用s2 == nil来判断

切片的切割

切割前后两个变量共享底层数组,对一个切片的修改会影响另一个切片的内容。

package main

import "fmt"

func main() {
	a1 := []int{23, 45, 12, 66, 77, 99}
	s3 := a1[2:]
	s4 := a1[:4]
	a1[3] = 6666
	fmt.Println(a1, s3, s4)
}

[23 45 12 6666 77 99] [12 6666 77 99] [23 45 12 6666]

切片的遍历

package main

import "fmt"

func main() {
	a1 := []int{23, 45, 12, 66, 77, 99}
	s3 := a1[:]
	a1[3] = 6666

	// 方式1
	for i := 0; i < len(s3); i++ {
		fmt.Println(s3[i])
	}

	fmt.Println()

	// 方式2
	for index, value := range s3 {
		fmt.Println(index, value)
	}
}

23
45
12
6666
77
99

0 23
1 45
2 12
3 6666
4 77
5 99

切片的扩容(append )

package main

import "fmt"

func main() {
	s1 := []string{"阿拉斯加", "哈士奇", "萨摩耶", "大黄", "小黑"}
	s1 = append(s1, "老王")       // 调用append函数必须使用原来的变量进行接收
	s1 = append(s1, "老张", "老李") // 调用append函数必须使用原来的变量进行接收

	s2 := []string{"王大审", "张大妈", "李大坡"}
	s1 = append(s1, s2...) // ...在Go表示打散,类似于python中的*

	fmt.Println(s1)
}

[阿拉斯加 哈士奇 萨摩耶 大黄 小黑 老王 老张 老李 王大审 张大妈 李大坡]

注意:调用append函数建议使用原来的变量进行接收

提示:...在Go表示打散,类似于python中的

copy函数

Go语言内建的copy()函数可以迅速地将一个切片的数据复制到另外一个切片空间中,copy()函数的使用格式如下:

 copy(destSlice, srcSlice []T)
  • srcSlice: 数据来源切片

  • destSlice: 目标切片

package main

import "fmt"

func main() {
	s1 := []string{"阿拉斯加", "哈士奇", "萨摩耶", "大黄", "小黑"}
	s2 := make([]string, 5, 10)
	copy(s2, s1) // 将切片s1中的元素复制到s2中
	fmt.Println(s1)
	fmt.Println(s2)

	s1[1] = "哈哥"
	fmt.Println(s1)
	fmt.Println(s2)
}

[阿拉斯加 哈士奇 萨摩耶 大黄 小黑]
[阿拉斯加 哈士奇 萨摩耶 大黄 小黑]
[阿拉斯加 哈哥 萨摩耶 大黄 小黑]
[阿拉斯加 哈士奇 萨摩耶 大黄 小黑]

从切片中删除元素

Go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。

package main

import "fmt"

func main() {
	// 从切片中删除元素
	arr1 := [...]int{1, 2, 3, 4, 5, 6, 7} // 数组
	s1 := arr1[:]                         // 切片
	// 要删除的元素索引为2
	s1 = append(s1[:2], s1[3:]...)
	fmt.Println(arr1) // append会修改底层的数组
	fmt.Println(s1)

}

[1 2 4 5 6 7 7]
[1 2 4 5 6 7]

注意:append会修改底层的数组。

总结:要从切片a中删除索引为index的元素,操作方法是a = append(a[:index], a[index+1:]...

练习

1.写出下面代码的结果

package main

import (
	"fmt"
)

func main() {
	var a = make([]int, 5, 10)
	fmt.Println(a)
	for i := 0; i < 10; i++ {
		a = append(a, i)
	}
	fmt.Println(a)

}

[0 0 0 0 0]
[0 0 0 0 0 0 1 2 3 4 5 6 7 8 9]
package main

import (
	"fmt"
)

func main() {
	var a = make([]string, 5, 10)
	fmt.Println(a)
	for i := 0; i < 10; i++ {
		a = append(a, fmt.Sprintf("%v", i))
	}
	fmt.Println(a)

}

[    ]
[     0 1 2 3 4 5 6 7 8 9]

2.使用内置的sort包对数组var a = [...]int{3, 7, 8, 9, 1}进行排序

package main

import (
	"fmt"
	"sort"
)

func main() {
	s6 := []int{3, 7, 8, 9, 1}
	sort.Ints(s6)
	fmt.Println(s6)

}

[1 3 7 8 9]

指针

任何程序数据载入内存后,在内存都有他们的地址,这就是指针。而为了保存一个数据在内存中的地址,我们就需要指针变量。

比如,“我喜欢你”这句话,我想把它写入程序中,程序一启动这句话是要加载到内存(假设内存地址0x123456),我在程序中把这段话赋值给变量A,把内存地址赋值给变量B。这时候变量B就是一个指针变量。通过变量A和变量B都能找到“我喜欢你”这句话。

Go语言中的指针不能进行偏移和运算,因此Go语言中的指针操作非常简单,我们只需要记住两个符号:&(取地址)和*(根据地址取值)。

package main

import (
	"fmt"
	"reflect"
)

func main() {
	n := 18
	p := &n // &符号表示取地址
	fmt.Println(n)
	fmt.Println(p, reflect.TypeOf(p)) //  *int表示int类型的指针

	m := *p //  *表示根据地址取值
	fmt.Println(m)
}

18
0xc0000aa058 *int
18

总结: 取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。

变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:

  • 对变量进行取地址(&)操作,可以获得这个变量的指针变量。

  • 指针变量的值是指针地址。

  • 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。

new和make

new

使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。

package main

import (
	"fmt"
)

func main() {
	// var a *int // a表示一个int类型的空指针
	a := new(int) // 表示给a开辟内存空间
	*a = 666      // 根据a的内存地址给a赋值
	fmt.Println(*a)
	fmt.Println(&a)
}

666
0xc000006028

开始的代码中var a *int只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。应该按照如下方式使用内置的new函数对a进行初始化之后就可以正常对其赋值了

make

make也是用于内存分配的,区别于new,它只用于slice、map以及channel的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。

new与make的区别

  1. 二者都是用来做内存分配的。

  2. make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;

  3. 而new用于值类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。

おすすめ

転載: blog.csdn.net/hpl980342791/article/details/125383794