ホームページ  >  記事  >  バックエンド開発  >  Golang のスライスを簡単に分析した記事

Golang のスライスを簡単に分析した記事

青灯夜游
青灯夜游転載
2022-12-05 19:12:495949ブラウズ

この記事ではGolangについて説明し、Go言語の基本であるスライス(Slice)についてお話しますので、お役に立てれば幸いです。

Golang のスライスを簡単に分析した記事

1. スライスの定義

前のセクションから、配列の長さは固定されており、長さは配列の は型の一部に属し、配列 a にはすでに 3 つの要素があり、配列 a に新しい要素を追加することはできなくなります。 js では配列に要素を追加したりその他の操作を行うのが普通ですが、go ではどうすればよいでしょうか?ここでは、今日私たちが焦点を当てているスライスについて説明します。 [プログラミング チュートリアルの推奨事項: プログラミング チュートリアル ]

スライスは、同じ型の要素の可変長シーケンスです。これは、配列タイプに基づくカプセル化の層です。非常に柔軟性があり、自動拡張をサポートしています。スライスは参照型であり、その内部構造には addresslengthcapacity が含まれます。スライスは通常、データのコレクションを迅速に操作するために使用されます。

スライス タイプを宣言するための基本的な構文は次のとおりです。

var name []T

このうち、

  • name: は変数名
  • T を表します。 : はスライス内の要素を表します Type
func main() {
   // 声明切片类型
   var a []string              //声明一个字符串切片
   var b = []int{}             //声明一个整型切片并初始化
   var c = []bool{false, true} //声明一个布尔切片并初始化
   var d = []bool{false, true} //声明一个布尔切片并初始化
   fmt.Println(a)              //[]
   fmt.Println(b)              //[]
   fmt.Println(c)              //[false true]
   fmt.Println(a == nil)       //true
   fmt.Println(b == nil)       //false
   fmt.Println(c == nil)       //false
   // fmt.Println(c == d)   //切片是引用类型,不支持直接比较,只能和nil比较
}

2. 単純なスライス式

スライスの最下層は配列であるため、配列に基づいてスライス式をスライスします。スライス式の lowhigh はインデックス範囲 (左は含まれ、右は含まれない) を表します。つまり、次の配列 a から 1 を持つ要素はスライス s を形成し、取得されたスライス <code> の長さは = high-low であり、容量は取得されたスライスの基になる配列の容量と等しくなります。 。

func main() {
	a := [5]int{1, 2, 3, 4, 5}
	s := a[1:3]  // s := a[low:high]
	fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
}



输出:
a[2:]  // 等同于 a[2:len(a)]
a[:3]  // 等同于 a[0:3]
a[:]   // 等同于 a[0:len(a)]

3. 完全なスライス式

配列の場合、配列へのポインタ、またはスライス (文字列にすることはできないことに注意してください)サポートされている完全なスライス式

a[low : high : max]

上記のコードは、単純なスライス式a[low: high]と同じタイプ、同じ長さ、および要素のスライスを構築します。さらに、結果のスライスの容量を max-low に設定します。完全なスライス式では最初のインデックス値 (低値) のみを省略できます。デフォルトは 0 です。

func main() {
	a := [5]int{1, 2, 3, 4, 5}
	t := a[1:3:5]
	fmt.Printf("t:%v len(t):%v cap(t):%v\n", t, len(t), cap(t))
}

输出:
t:[2 3] len(t):2 cap(t):4

完全なスライス式が満たす必要がある条件は、0 <= low <= high <= max <= cap(a)、その他の条件と単純なスライスです。表現も同じ。

4. make() 関数を使用してスライスを構築します

私たちはすべて、配列に基づいてスライスを作成しました。スライスを動的に作成する必要がある場合は、次のものが必要です。使用する組み込み make() 関数の形式は次のとおりです:

make([]T, size, cap)

その中に:

  • T: スライス ## の要素タイプ
  • #size: スライス内の要素の数
  • cap: スライスの容量
  • func main() {
    	a := make([]int, 2, 10)
    	fmt.Println(a)      //[0 0]
    	fmt.Println(len(a)) //2
    	fmt.Println(cap(a)) //10
    }
上記のコードでは、

a の 10 個の内部ストレージ領域割り当てられていますが、実際に個別に使用されるのは 2 つだけです。容量は現在の要素の数に影響しないため、len(a) は 2 を返し、cap(a) はスライスの容量を返します。

5. スライスが空かどうかを判断する

スライスの本質は、基礎となる配列をカプセル化することであり、これには 3 つの情報が含まれています: 基礎となる配列のポインター配列とスライスの長さ (len) とスライスの容量 (cap)。

スライスを比較できません。

== 演算子を使用して、2 つのスライスにすべて等しい要素が含まれているかどうかを判断することはできません。スライスに対する唯一の正当な比較演算は、nil を使用したものです。 nil 値のスライスには基礎となる配列がなく、nil 値のスライスの長さと容量は両方とも 0 です。ただし、次の例のように、長さと容量が 0 のスライスが nil である必要があるとは言えません。

var s1 []int         //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{}        //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil

スライスが空かどうかを確認するには、常に

を使用します。 s == nil の代わりに len( s) == 0 になります。

6. スライスの代入コピー

コピーの前後の 2 つの変数は、基礎となる配列を共有します。1 つのスライスを変更すると、別のスライスの内容に影響します。これには、次のことが必要です。特別な注意を払ってください。

func main() {
	s1 := make([]int, 3) //[0 0 0]
	s2 := s1             //将s1直接赋值给s2,s1和s2共用一个底层数组
	s2[0] = 100
	fmt.Println(s1) //[100 0 0]
	fmt.Println(s2) //[100 0 0]
}

7. スライス トラバーサル

スライスのトラバーサル方法は配列のトラバーサル方法と同じで、インデックス トラバーサルと

for range トラバーサルをサポートします。 。

func main() {
	s := []int{1, 3, 5}

	for i := 0; i < len(s); i++ {
		fmt.Println(i, s[i])
	}

	for index, value := range s {
		fmt.Println(index, value)
	}
}

8. append() メソッドは要素をスライスに追加します

Go 言語の組み込み関数

append()は動的に追加できます要素をスライスに追加します。一度に 1 つの要素を追加することも、複数の要素を追加することも、別のスライスから要素を追加することもできます (その後に...)。

func main(){
	var s []int
	s = append(s, 1)        // [1]
	s = append(s, 2, 3, 4)  // [1 2 3 4]
	s2 := []int{5, 6, 7}  
	s = append(s, s2...)    // [1 2 3 4 5 6 7]
}

var を通じて宣言されたゼロ値のスライスは、初期化せずに

append() 関数で直接使用できます。

var s []ints = append(s, 1, 2, 3)

每个切片会指向一个底层数组,这个数组的容量够用就添加新增元素。当底层数组不能容纳新增的元素时,切片就会自动按照一定的策略进行“扩容”,此时该切片指向的底层数组就会更换。“扩容”操作往往发生在append()函数调用时,所以我们通常都需要用原变量接收append函数的返回值。

9.使用copy()函数复制切片

由于切片是引用类型,所以a和b其实都指向了同一块内存地址。修改b的同时a的值也会发生变化。

func main() {
	a := []int{1, 2, 3, 4, 5}
	b := a
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(b) //[1 2 3 4 5]
	b[0] = 1000
	fmt.Println(a) //[1000 2 3 4 5]
	fmt.Println(b) //[1000 2 3 4 5]
}

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

copy(destSlice, srcSlice []T)

其中:

  • srcSlice: 数据来源切片
  • destSlice: 目标切片
func main() {
	// copy()复制切片
	a := []int{1, 2, 3, 4, 5}
	c := make([]int, 5, 5)
	copy(c, a)     //使用copy()函数将切片a中的元素复制到切片c
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1 2 3 4 5]
	c[0] = 1000
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1000 2 3 4 5]
}

10.从切片中删除元素

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

func main() {
	// 从切片中删除元素
	a := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// 要删除索引为2的元素
	a = append(a[:2], a[3:]...)
	fmt.Println(a) //[30 31 33 34 35 36 37]
}

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

结束:

再次提醒,需要进技术交流群的同学,可以加我微信fangdongdong_25,需要进前端工程师交流群的备注“前端”,需要进go后端交流群的备注“go后端”

【相关推荐:Go视频教程

以上がGolang のスライスを簡単に分析した記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。