技術共有

【Goシリーズ】配列、スライス、マップ

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

前と次を繋ぐ

前回の記事でifとforを紹介しましたが、これは実践してはいけません。continue 100以内の偶数の合計を計算する文です。コードを書くとき、continueこのステートメントは、必要のない特定の反復をスキップするのに役立ちます。たとえば、この例では、すべての奇数をスキップします。

  1. sum := 0
  2. for i := 1; i < 100; i++{
  3. if i & 1 == 0 {
  4. continue
  5. }
  6. sum += i
  7. }
  8. fmt.Println("the sum is",sum)

学習を開始する

プログラミングでは、同じ型の要素のセットを扱う必要があることがよくありますが、これらの要素のセットは Go 言語の特定のデータ構造で表されます。今日は、Go のいくつかのコレクション型 (配列、スライス、マップ) を詳しく紹介します。

配列

まず、配列から始めましょう。配列は Go の最も基本的なデータ構造であり、同じ型の要素の固定長のシーケンスです。配列が宣言されると、その長さは変更できません。配列の宣言と初期化は非常に簡単です。

配列の宣言

配列を宣言するときは、配列の型と配列の長さを指定する必要があります。配列の宣言方法は次のとおりです。

var arrayName [arrayLength]elementType

たとえば、長さ 5 の整数配列を宣言します。

var numbers [5]int
配列を初期化する

配列はさまざまな方法で初期化できます。

  • リテラル初期化を使用します。
var numbers = [5]int{1, 2, 3, 4, 5}
  • 使用:=短い声明:
numbers := [5]int{1, 2, 3, 4, 5}
  • 配列の長さを自動的に推測します。
numbers := [...]int{1, 2, 3, 4, 5}
  • インデックスの初期化を指定します。
numbers := [5]int{0: 1, 4: 5}

アレイの特徴

  • 固定長: 配列の長さは宣言時に決定され、後で変更することはできません。
  • 同じタイプの要素: 配列には同じタイプの要素のみを含めることができます。
  • 連続したメモリ割り当て: 配列要素はメモリ内で連続的に割り当てられるため、配列要素へのアクセスが非常に効率的になります。

配列要素にアクセスする

配列内の要素には、0 から始まるインデックスによってアクセスできます。

value := numbers[2] // 获取索引为 2 的元素

トラバース配列

使用できますfor配列内のすべての要素をループします。

  1. for i, value := range numbers {
  2. fmt.Printf("Index: %d, Value: %dn", i, value)
  3. }

配列の長さ

内蔵のものを使用できますlen配列の長さを取得する関数:

length := len(numbers)

配列のゼロ値

配列が明示的に初期化されていない場合、その要素は自動的にその型のゼロ値に設定されます。たとえば、整数配列のゼロ値は 0 です。

var numbers [5]int // 所有元素都是 0

多次元配列

Go 言語は多次元配列もサポートしています。以下は、2x3 整数配列を宣言して初期化する例です。

  1. var matrix [2][3]int
  2. matrix = [2][3]int{{1, 2, 3}, {4, 5, 6}}

配列の制限事項

配列の長さは固定されているため、場合によってはあまり柔軟ではない可能性があります。可変長のコレクションが必要な場合は、スライスを使用できます。

スライス

次はスライスです。これは、動的配列と考えることができる、より柔軟な組み込み型です。スライスの長さは可変で、配列に基づいて作成されるため、より便利です。スライスを宣言して初期化する方法は次のとおりです。

  1. s := make([]int, 3) // 创建一个长度为3的整型切片
  2. s[0] = 1 // 切片元素赋值
  3. s[1] = 2
  4. s[2] = 3
  5. s = append(s, 4) // 向切片追加元素

Go 言語では、配列とスライスはどちらも同じ型の一連の要素を格納するために使用されますが、メモリ割り当て、サイズの変動性、および使用法には大きな違いがあります。配列とスライスの主な違いは次のとおりです。

サイズのばらつき

  • 配列 : 配列のサイズは宣言時に決定され、後で変更することはできません。配列のサイズはその型の一部であるため、[3]intそして[4]intは異なるタイプです。
  • スライス : スライスは動的であり、実行時に拡大または縮小する可能性があります。スライスのサイズはそのタイプの一部ではないため、[]intすべての整数スライスに共通のタイプです。

メモリ割り当て

  • 配列 : 配列は値型であり、配列が関数パラメータとして渡されると、その値のコピーが渡されます。これは、関数内で配列を変更しても、元の配列には影響しないことを意味します。
  • スライス : スライスは参照型であり、基になる配列へのポインタ、スラ​​イスの長さと容量が含まれます。スライスが関数パラメータとして渡される場合、ポインタのコピーが渡されるため、関数内でスライスを変更すると元のスライスに影響します。

初期化

  • 配列: 配列を初期化するときは、そのサイズを指定する必要があり、要素の値をすぐに割り当てることができます。
  • スライス: スライスはリテラルを介して渡すことができます。make初期化する関数または配列のスライス。サイズは指定されていません。

サンプルコード

配列とスライスの初期化の例を次に示します。

  1. // 数组
  2. var arr [3]int = [3]int{1, 2, 3}
  3. // 切片
  4. var slice []int = []int{1, 2, 3}
  5. // 或者使用 make 函数
  6. slice := make([]int, 3)

機能の違い

  • 配列: サイズが固定されているため、配列のサイズはコンパイル時にわかり、スタック上の配列にメモリを割り当てることができ、配列要素にアクセスする時間計算量は O(1) です。
  • スライス: スライスにより柔軟性が向上します。append関数は要素を追加するか、スライス操作を通じてサブスライスを取得します。スライスの基礎となる配列はヒープ上に割り当てられる可能性があり、スライス要素にアクセスする時間計算量も O(1) ですが、append基になる配列の再割り当てが発生する可能性があり、これは通常 O(n) 操作です。

マッピング

最後にマッピングを見てみましょう。マップは、キーを値にマップする Go の連想配列です。マップのキーには、整数、浮動小数点数、文字列、ポインター、インターフェイス (インターフェイス内に含まれる値が同等である限り)、構造体、配列など、等価演算子でサポートされる任意の型を使用できます。マップされた値は任意の型にすることができます。

宣言と初期化

マップを宣言する

マップを宣言するための構文は次のとおりです。

var mapName map[keyType]valueType

たとえば、キーを文字列として、値を整数としてマップを宣言します。

var scores map[string]int
マップの初期化

マップを宣言した後、渡す必要がありますmake関数を使用して初期化して使用できるようにします。

scores = make(map[string]int)

あるいは、短い宣言を使用して初期化することもできます。

scores := make(map[string]int)

宣言時の初期化にリテラルを使用することもできます。

  1. scores := map[string]int{
  2. "alice": 90,
  3. "bob": 85,
  4. "charlie": 88,
  5. }

マップの特徴

  • キーの一意性: マップでは、各キーは一意です。既存のキーを挿入しようとすると、キーに対応する値が更新されます。
  • 障害:map は順序付けされていないため、マップが反復されるたびに要素の順序が異なる場合があります。
  • 動的サイズ:マップのサイズは動的であり、必要に応じてキーと値のペアを追加または削除できます。
  • 参照型: Map は参照型であり、map を関数に渡すとき、実際に渡すのは基になるデータ構造へのポインタです。

運行マップ

要素の追加
scores["alice"] = 90
要素の取得
value := scores["alice"]

キーが存在しない場合は、その値タイプのゼロ値が返されます。

キーが存在するかどうかを確認する

カンマ -ok イディオムを使用して、キーがマップ内に存在するかどうかを確認できます。

  1. value, exists := scores["alice"]
  2. if exists {
  3. // 键存在
  4. } else {
  5. // 键不存在
  6. }
要素の削除

使用delete関数はマップからキーと値のペアを削除できます。

delete(scores, "alice")

キーが存在しない場合は、deleteこの関数は何も行いません。

マップを横断する

使用forループはマップ内のすべてのキーと値のペアを横断できます。

  1. for key, value := range scores {
  2. fmt.Printf("%s: %dn", key, value)
  3. }

マップのゼロ値

マップのゼロ値はnil 。1つnilマップには基礎となるデータ構造がないため、要素を追加できません。マップに要素を追加する前に、次を使用する必要があります。make初期化してください。

マップの長さ

内蔵のものを使用できますlenマップ内のキーと値のペアの数を取得する関数:

length := len(scores)

マップキーの種類

マップのキーには、整数、浮動小数点数、文字列、ポインター、インターフェイス (インターフェイス内に含まれる値が同等である限り)、構造体、配列など、同等のタイプを使用できます。スライス、マップ、関数は等価比較をサポートしていないため、マップ キーとして使用できません。

間違いを犯しやすい

Go 言語では、配列、スライス、マップが一般的に使用される 3 つのデータ構造であり、それぞれに異なる特性と考慮事項があります。使用する際の注意点は次のとおりです。

配列

  • 大きすぎる配列は多くのスタック領域を占有し、スタック オーバーフローを引き起こす可能性があるため、使用しないでください。
  • 配列は、固定サイズのデータ​​のコレクションが必要な場合に使用されます。

スライス

  • スライスが拡張されると、メモリの再割り当てが発生する可能性があります。頻繁な拡張を避けるために、十分な容量を事前に割り当ててください。
  • 大きすぎるスライスは大量のヒープ領域を占有する可能性があるため、使用しないでください。
  • スライスのゼロ値はnil、使用前に初期化する必要があります。

地図

  • マップのゼロ値はnilnilMap はキーと値のペアの保存には使用できないため、使用前に初期化する必要があります。
  • 同時環境では、マップ上の読み取りおよび書き込み操作はスレッドセーフではないため、ミューテックス ロックまたはその他の同期メカニズムを使用して保護する必要があります。
  • 使用delete存在しないキーを削除してもエラーは生成されませんが、キーが存在するかどうかを確認することは安全です。