初心者でもわかる!Go言語のrange機能の使い方7選

初心者が学ぶGo言語のrange機能のイラストGo言語
この記事は約12分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Go言語は現代のプログラミング言語の中でも特に注目されている言語の一つです。

その中でも、range機能はGo言語の強力な機能の一つであり、初心者から上級者まで幅広いプログラマーにとって重要な概念です。

この記事を読むことで、Go言語のrange機能の基本から応用までを理解し、さまざまな状況での使用方法を学ぶことができます。

range機能は配列やスライス、マップなどのコレクションを簡単に扱うことができるため、Go言語において非常に便利なツールです。

●Go言語のrange機能とは

Go言語のrange機能は、配列、スライス、マップ、文字列などのコレクションを繰り返し処理するためのシンプルで強力な構文です。

forループと組み合わせて使用され、コレクションの各要素にアクセスするための簡潔な方法を提供します。

rangeは、コレクションの長さや内容を事前に知る必要なく、その要素を一つずつ取り出して処理することができます。

○range機能の基本

range機能の基本的な使い方は非常にシンプルです。

for文と組み合わせて使用され、コレクションの各要素を反復処理します。

例えば、配列やスライスの場合、rangeは各要素のインデックスと値を返します。

マップの場合には、キーと値を返します。

このシンプルさがGo言語のrange機能を非常に強力かつ便利なツールにしています。

○range機能の用途

range機能は多くの用途に使われます。

例えば、配列やスライスの要素を繰り返し処理する際、インデックスと値の両方が必要な場合や、マップのすべてのキーと値にアクセスする必要がある場合に非常に便利です。

また、文字列を文字単位で繰り返し処理する際にも使用されます。

さらに、range機能は条件付きの繰り返し処理やデータのフィルタリング、変換にも役立ちます。

これらの用途により、Go言語のプログラミングにおいてrange機能は不可欠な存在となっています。

●rangeを使った基本的なサンプルコード

Go言語でのrange機能は、繰り返し処理を行う際に非常に便利なツールです。

この機能を使うことで、コードをより読みやすく、効率的にすることができます。

ここでは、rangeを使用した基本的なサンプルコードをいくつか紹介し、それぞれのコードについて詳細な説明を加えます。

○サンプルコード1:配列でのrangeの使用

配列でのrangeの使用は最も基本的なパターンの一つです。

下記のサンプルコードは、整数の配列をループし、各要素を出力しています。

package main

import "fmt"

func main() {
    numbers := []int{2, 3, 5, 7, 11, 13}

    for i, number := range numbers {
        fmt.Printf("Index: %d, Value: %d\n", i, number)
    }
}

このコードでは、numbers という名前の整数型のスライスを定義しています。

for i, number := range numbers 行で、rangeを使用して配列の各要素にアクセスし、そのインデックス(i)と値(number)を出力しています。

○サンプルコード2:スライスでのrangeの使用

スライスでもrangeを使用することができます。

下記のサンプルコードは、文字列のスライスをループし、各要素を出力しています。

package main

import "fmt"

func main() {
    fruits := []string{"apple", "banana", "cherry"}

    for i, fruit := range fruits {
        fmt.Printf("Index: %d, Fruit: %s\n", i, fruit)
    }
}

このコードでは、fruits という名前の文字列型のスライスを定義し、rangeを使ってスライスの各要素をループしています。

インデックス(i)と値(fruit)がそれぞれ出力されます。

○サンプルコード3:マップでのrangeの使用

マップに対してもrangeを使用することができます。

下記のサンプルコードでは、キーと値が文字列型のマップをループしています。

package main

import "fmt"

func main() {
    capitals := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo"}

    for country, capital := range capitals {
        fmt.Printf("The capital of %s is %s\n", country, capital)
    }
}

このコードでは、国とその首都を表すマップcapitalsを定義しています。

for country, capital := range capitals 行で、マップの各要素(国名と首都)にアクセスし、それらを出力しています。

●rangeの応用例

Go言語におけるrangeの応用は、基本的な使い方を超えて多様なシナリオに対応できます。

ここでは、rangeを使用した応用的なサンプルコードをいくつか紹介します。

これらの例を通じて、rangeのさらに高度な使い方を理解し、Go言語のプログラミングスキルを向上させることができます。

○サンプルコード4:rangeを使った複数の値の処理

rangeを使用して複数の値を同時に処理することも可能です。

下記のサンプルコードは、キーと値のペアを持つマップをループし、各ペアの処理を行っています。

package main

import "fmt"

func main() {
    temperatures := map[string]float64{"Tokyo": 17.0, "Paris": 18.5, "New York": 16.0}

    for city, temp := range temperatures {
        fmt.Printf("%s's temperature: %.1f°C\n", city, temp)
    }
}

このコードでは、各都市の気温を表すtemperaturesマップを定義し、rangeを使って各都市とその気温をループしています。

この例では、マップの各要素を効率的に処理しています。

○サンプルコード5:rangeを使った条件付きループ

rangeを使用して条件付きでループ処理を行うこともできます。

下記のサンプルコードは、特定の条件に基づいてスライスの要素をフィルタリングしています。

package main

import "fmt"

func main() {
    numbers := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}

    for _, number := range numbers {
        if number > 15 {
            fmt.Printf("Found a number greater than 15: %d\n", number)
        }
    }
}

このコードでは、整数のスライスnumbersを定義し、rangeを使って各要素をループしています。

ループの中で、if文を使用して15より大きい数を見つけた場合にのみ処理を行っています。

○サンプルコード6:rangeと関数を組み合わせた使用法

Go言語におけるrange機能は、関数と組み合わせてより高度な操作を行うことができます。

下記のサンプルコードは、スライスの各要素に関数を適用し、結果を出力する方法を表しています。

package main

import (
    "fmt"
    "strings"
)

func main() {
    words := []string{"hello", "world", "go", "language"}

    for _, word := range words {
        upperWord := strings.ToUpper(word)
        fmt.Println(upperWord)
    }
}

このコードでは、strings.ToUpper関数を使用して、スライス内の各文字列を大文字に変換しています。

rangeを用いることで、スライスの各要素に対して一貫した操作を簡単に適用することが可能になります。

○サンプルコード7:rangeを使ったパターンマッチング

rangeはパターンマッチングのシナリオにも有効に使用できます。

下記のサンプルコードでは、特定のパターンに一致する要素を探し出す方法を表しています。

package main

import (
    "fmt"
    "strings"
)

func main() {
    fruits := []string{"apple", "banana", "cherry", "date"}

    for _, fruit := range fruits {
        if strings.HasPrefix(fruit, "b") {
            fmt.Println("Found fruit with b:", fruit)
        }
    }
}

このコードでは、strings.HasPrefix関数を使用して、”b”で始まる果物をスライスから探し出しています。

rangeを使用することで、スライス内の各要素を効率的に走査し、特定の条件に基づいて処理を行うことができます。

●rangeの注意点と対処法

Go言語のrange機能を使う際には、特定の注意点があります。

これらの点を理解し、適切に対処することが重要です。

rangeを使うときによくある間違いや、パフォーマンスに関する問題を避けるための方法を詳しく見ていきましょう。

○rangeの使用時の一般的な誤解

rangeを使う際には、いくつかの誤解があります。

まず、rangeループ内で要素を変更しても、元のコレクションには影響しないことがあります。

これは、rangeが元のコレクションのコピーを作成してイテレーションするためです。

したがって、元のコレクションを変更する必要がある場合は、インデックスを直接使ってアクセスする必要があります。

また、rangeループ中にコレクション自体を変更すると、予期しない動作やエラーが発生することがあります。

これは、コレクションの構造が変わることで、イテレーションのプロセスが妨げられるためです。

さらに、range内で同じ変数が再利用されることも理解しておく必要があります。

これは、特にゴルーチン内でrange変数を使う場合に、問題を引き起こす可能性があるためです。

○パフォーマンスに関する注意点

rangeを使う際のパフォーマンスに関する重要な点として、大きなコレクションの扱いがあります。

特に大きな構造体を含むスライスをrangeでループする場合、各イテレーションでのコピーがパフォーマンスに影響を与えることがあります。

これを避けるためには、構造体のポインタを使ってループすることが効果的です。

これにより、不必要なコピーを減らし、メモリ使用量を削減し、パフォーマンスを向上させることができます。

また、rangeループ中にコレクションの長さを変更することは避けるべきです。これは、ループの動作が予期せぬ結果を引き起こす可能性があるためです。

これらの点を考慮することで、Go言語でのrangeの使用時に効率的かつ安全なコードを書くことができます。

●rangeのカスタマイズ方法

Go言語のrange機能は、その使い方をカスタマイズすることで、さまざまな場面での応用が可能になります。

ここでは、カスタムrange関数の作成方法とrangeの動作をカスタマイズするテクニックについて解説します。

これにより、標準のrange機能だけでは実現できないような独自の処理を行うことができるようになります。

○カスタムrange関数の作成

Go言語では、range機能を拡張するために独自の関数を作成することができます。

例えば、特定の条件を満たす要素だけを処理するカスタムrange関数を作成することが可能です。

下記のサンプルコードでは、偶数のみを処理するカスタムrange関数を表しています。

package main

import "fmt"

func rangeEvenNumbers(numbers []int, action func(int)) {
    for _, num := range numbers {
        if num%2 == 0 {
            action(num)
        }
    }
}

func main() {
    numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    rangeEvenNumbers(numbers, func(n int) {
        fmt.Println(n, "is even")
    })
}

このコードでは、rangeEvenNumbers関数が配列内の偶数のみを処理します。

これにより、標準のrange機能にはない、特定の条件に基づく処理を簡単に実装することができます。

○rangeの動作をカスタマイズするテクニック

rangeの動作をカスタマイズする別の方法として、インデックスや値を無視するテクニックがあります。

例えば、値のみが必要でインデックスは不要な場合、下記のようにアンダースコア(_)を使用してインデックスを無視することができます。

package main

import "fmt"

func main() {
    fruits := []string{"apple", "banana", "cherry"}

    for _, fruit := range fruits {
        fmt.Println("Fruit:", fruit)
    }
}

このコードでは、for _, fruit := range fruitsの部分で、インデックスは無視され、値のみが利用されています。

このように、必要な情報のみを取り出すことで、コードの可読性を高めることができます。

まとめ

この記事では、Go言語のrange機能の基本から応用、注意点、カスタマイズ方法までを詳しく解説しました。

rangeはGo言語の中でも特に強力な機能の一つで、正しく理解し活用することで、プログラミングの幅が大きく広がります。

初心者から上級者まで、Go言語のrange機能を使いこなすことで、より効率的で読みやすいコードを書くことができるでしょう。