Goで変数と定数を使用する方法

変数は、マスターすることが重要なプログラミングの概念です。変数は、プログラムで使用している値の代わりになる記号です。

このチュートリアルでは、変数の基本と、作成するGoプログラム内での変数のベストプラクティスについて説明します。

変数の理解

技術的には、変数は記憶場所を値に割り当て、それをシンボリック名または識別子に関連付けることです。コンピュータプログラム内でその保存された値を参照するために変数名を使用します。

変数は、値に結びつけられた名前のついたラベルと考えることができます。

例えば、整数1032049348があり、長い数字を繰り返し入力する代わりに変数に保存したいとします。これを実現するために、変数iのように覚えやすい名前を使用できます。値を変数に保存するには、次の構文を使用します:

i := 1032049348

この変数は、値に結びつけられたラベルのようなものと考えることができます。

このラベルには変数名iが書かれており、整数値1032049348に結びつけられています。

フレーズi := 1032049348は、いくつかの部分からなる宣言と代入文です:

  • 変数名(i
  • 短い変数宣言代入(:=
  • 変数名に関連付けられている値(1032049348
  • Goによって推論されたデータ型(int

次のセクションでは、型を明示的に設定する方法を見ていきます。

これらの部分が合わさって、変数iを整数1032049348の値と等しくするステートメントを構成しています。

変数に値を等しく設定するとすぐに、その変数を初期化または作成します。それが済んだら、値の代わりに変数を使用する準備が整います。

一度i1032049348の値に等しく設定したら、整数の代わりにiを使用できるので、それを出力してみましょう:

package main

import "fmt"

func main() {
	i := 1032049348
	fmt.Println(i)
}
Output
1032049348

また、変数を使って簡単かつ迅速に数学的な計算を行うこともできます。i := 1032049348を使って、以下の構文で整数値813を引くことができます:

fmt.Println(i - 813)
Output
1032048535

この例では、Goが計算を行い、変数iから813を引いて合計1032048535を返します。

数学の話になると、変数は数学的な方程式の結果に等しく設定することができます。2つの数値を足して、その合計の値を変数xに格納することもできます:

x := 76 + 145

この例は代数に似ていることに気づかれたかもしれません。数式や方程式内で数字や数量を表すために文字や他の記号を使用するのと同じように、変数はデータ型の値を表す記号的な名前です。Goの正しい構文のために、変数がどの方程式の左側にあるかを確認する必要があります。

それでは、xを出力してみましょう:

package main

import "fmt"

func main() {
	x := 76 + 145
	fmt.Println(x)
}
Output
221

Goが221という値を返したのは、変数x76145の合計に等しく設定されたためです。

変数は整数だけでなく、あらゆるデータ型を表すことができます:

s := "Hello, World!"
f := 45.06
b := 5 > 9 // ブール値はtrueまたはfalseのいずれかを返します
array := [4]string{"item_1", "item_2", "item_3", "item_4"}
slice := []string{"one", "two", "three"}
m := map[string]string{"letter": "g", "number": "seven", "symbol": "&"}

これらの変数のいずれかを出力すると、Goはその変数が等価なものを返します。文字列sliceデータ型の代入文を使ってみましょう:

package main

import "fmt"

func main() {
	slice := []string{"one", "two", "three"}
	fmt.Println(slice)
}
Output
[one two three]

スライスの値[]string{"one", "two", "three"}を変数sliceに代入し、その値をfmt.Println関数を使ってsliceを呼び出すことで出力しました。

変数は、コンピュータ内のメモリの小さな領域を確保し、その領域に指定された値を受け入れ、そのスペースに関連付けます。

変数の宣言

Goでは、変数を宣言する方法がいくつかあり、場合によっては同じ変数と値を宣言する方法が複数あります。

データ型intの変数iを初期化せずに宣言することができます。つまり、値を入れるスペースを宣言しますが、初期値は与えません:

var i int

これにより、データ型intの変数iが宣言されます。

値を初期化するために、等号(=)演算子を使用することができます。以下の例のようにです:

var i int = 1

Go言語では、これらの宣言形式はどちらも長い変数宣言と呼ばれています。

また、短い変数宣言を使用することもできます:

i := 1

この場合、変数iとデータ型intがあります。データ型を指定しない場合、Goはデータ型を推測します。

変数を宣言する三つの方法を用いて、Goコミュニティは以下の慣習を採用しています:

  • 変数を初期化しない場合にのみ、長い形式var i intを使用します。

  • 宣言と初期化を行う場合には、短い形式i := 1を使用します。

  • Goにデータ型を推測させたくないが、短い変数宣言を使用したい場合は、希望する型で値をラップすることができます。以下の構文で行います:

i := int64(1)

値を初期化する際に長い変数宣言形式を使用することは、Goでは慣用的ではありません:

var i int = 1

Goコミュニティが通常どのように変数を宣言するかを守ることは、他の人がプログラムをスムーズに読めるようにするための良い習慣です。

ゼロ値

すべての組み込み型にはゼロ値があります。割り当てられた変数は、値が一度も割り当てられていなくても使用できます。以下の型のゼロ値を見ることができます:

package main

import "fmt"

func main() {
	var a int
	var b string
	var c float64
	var d bool

	fmt.Printf("var a %T = %+v\n", a, a)
	fmt.Printf("var b %T = %q\n", b, b)
	fmt.Printf("var c %T = %+v\n", c, c)
	fmt.Printf("var d %T = %+v\n\n", d, d)
}
Output
var a int = 0 var b string = "" var c float64 = 0 var d bool = false

私たちはfmt.Printfステートメントで%T動詞を使用しました。これは、関数に変数のデータ型を出力するように指示します。

Goでは、すべての値がゼロ値を持っているため、他のいくつかの言語のように未定義の値を持つことはできません。例えば、他の言語ではブーリアン未定義、またはになることができ、変数に3つの状態を許容します。Goでは、ブーリアン値に対して2つ以上の状態を持つことはできません。

変数の命名:ルールとスタイル

変数の命名はかなり柔軟ですが、留意すべきいくつかのルールがあります:

  • 変数名は1つの単語である必要があります(スペースがないことを意味します)。
  • 変数名は、文字、数字、およびアンダースコア(_)のみで構成されている必要があります。
  • 変数名を数字で始めることはできません。

これらのルールに従って、有効な変数名と無効な変数名の両方を見てみましょう:

Valid Invalid Why Invalid
userName user-name Hyphens are not permitted
name4 4name Cannot begin with a number
user $user Cannot use symbols
userName user name Cannot be more than one word

さらに、変数の命名時には大文字と小文字が区別されることに注意してください。これらの名前 userNameUSERNAMEUserName、および uSERnAME はすべて完全に異なる変数です。プログラム内で類似した変数名を使用しないことがベストプラクティスです。これにより、現在および将来の共同作業者と自分自身が変数を整理しやすくなります。

変数は大文字と小文字を区別しますが、Go では変数の最初の文字の大文字と小文字には特別な意味があります。変数が大文字で始まる場合、その変数は宣言されたパッケージの外からアクセス可能です(または exported)。変数が小文字で始まる場合、それは宣言されたパッケージ内でのみ利用可能です。

var Email string
var password string

Email は大文字で始まり、他のパッケージからアクセスできます。password は小文字で始まり、宣言されたパッケージ内でのみアクセス可能です。

Go では非常に簡潔な(または短い)変数名を使用するのが一般的です。変数に userNameuser のどちらを使用するかを選ぶ場合、user を選ぶのが慣用的です。

スコープも変数名の簡潔さに影響を与えます。ルールは、変数が存在するスコープが小さいほど、変数名も小さくなるというものです。

names := []string{"Mary", "John", "Bob", "Anna"}
for i, n := range names {
	fmt.Printf("index: %d = %q\n", i, n)
}

大きなスコープでnames変数を使用しているため、プログラム内でその意味を覚えやすくするために、より意味のある名前を付けるのが一般的です。ただし、in変数は次の行ですぐに使用され、その後再び使用されません…このため、コードを読む人が変数がどこで使用されているのか、またそれらが何を意味するのかについて混乱することはありません。

次に、変数スタイルに関するいくつかの注意点を説明します。スタイルは、複数の単語からなる名前にはアンダースコアではなくMixedCapsまたはmixedCapsを使用することです。

Conventional Style Unconventional Style Why Unconventional
userName user_name Underscores are not conventional
i index prefer i over index as it is shorter
serveHTTP serveHttp acronyms should be capitalized

スタイルについて最も重要なことは、一貫性を保ち、チームがそのスタイルに同意することです。

変数の再代入

「変数」という言葉が示すように、Goの変数は容易に変更できます。これは、以前に代入された変数に異なる値を再代入することができることを意味します。再代入が可能であることは、プログラムの過程ですでに初期化された変数にユーザー生成の値を受け入れる必要がある場合や、以前に定義されたものに代入を変更する必要がある場合に便利です。

すでに定義されている変数が不明な場合、他の人が書いた大規模なプログラムを扱う際に、変数を容易に再代入できることを知っておくと役立ちます。

int型の変数i76の値を代入し、次に42の新しい値を代入しましょう:

package main

import "fmt"

func main() {
	i := 76
	fmt.Println(i)

	i = 42
	fmt.Println(i)
}
Output
76 42

この例は、まず変数iに整数値を代入し、次に42の値を代入して変数iを再代入できることを示しています。

注意:変数を宣言して初期化する際には:=を使用できますが、すでに宣言された変数の値を単に変更する場合は等号演算子(=)のみを使用する必要があります。

Goは型付き言語であるため、ある型を別の型に代入することはできません。例えば、int型の変数に"Sammy"の値を代入することはできません:

i := 72
i = "Sammy"

異なる型を互いに代入しようとすると、コンパイル時エラーが発生します:

Output
cannot use "Sammy" (type string) as type int in assignment

Goでは、変数名を複数回使用することは許可されていません:

var s string
var s string
Output
s redeclared in this block

同じ変数名に対して短い変数宣言を複数回使用しようとすると、コンパイルエラーも発生します。これは誤って発生する可能性があるため、エラーメッセージの意味を理解することが役立ちます:

i := 5
i := 10
Output
no new variables on left side of :=

変数宣言と同様に、変数の命名に配慮することで、将来あなたや他の人がプログラムを再訪した際の可読性が向上します。

複数代入

Goでは、同じ行内で複数の変数に複数の値を割り当てることができます。これらの値はそれぞれ異なるデータ型であっても構いません:

j, k, l := "shark", 2.05, 15
fmt.Println(j)
fmt.Println(k)
fmt.Println(l)
Output
shark 2.05 15

この例では、変数jに文字列"shark"が割り当てられ、変数kに浮動小数点数2.05が割り当てられ、変数lに整数15が割り当てられています。

この方法で1行で複数の変数に複数の値を割り当てることで、コードの行数を減らすことができます。ただし、コードの行数を減らすために可読性を犠牲にしないことが重要です。

グローバル変数とローカル変数

プログラム内で変数を使用する際には、変数のスコープを念頭に置くことが重要です。変数のスコープとは、特定のプログラムのコード内でその変数にアクセスできる特定の場所を指します。つまり、すべての変数が特定のプログラムのすべての部分からアクセスできるわけではなく、一部の変数はグローバルであり、一部はローカルであるということです。

グローバル変数は関数の外側に存在します。ローカル変数は関数の内側に存在します。

グローバル変数とローカル変数の動作を見てみましょう:

package main

import "fmt"


var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
}

func main() {
	printLocal()
	fmt.Println(g)
}
Output
local global

ここでは、var g = "global"を使って関数の外でグローバル変数を作成します。次に、printLocal()という関数を定義します。関数の内部では、lというローカル変数が割り当てられ、その後出力されます。プログラムはprintLocal()を呼び出し、その後グローバル変数gを出力することで終了します。

なぜなら、gはグローバル変数であるため、printLocal()内で参照することができます。前のプログラムをそのように修正してみましょう:

package main

import "fmt"


var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
	fmt.Println(g)
}

func main() {
	printLocal()
	fmt.Println(g)
}
Output
local global global

まず、グローバル変数gを宣言します、var g = "global"main関数では、printLocal関数を呼び出し、その中でローカル変数lを宣言し、出力します、fmt.Println(l)。その後、printLocalはグローバル変数gを出力します、fmt.Println(g)gprintLocal内で定義されていないにもかかわらず、グローバルスコープで宣言されているためアクセスできます。最後に、main関数もgを出力します。

次に、関数の外でローカル変数を呼び出してみましょう:

package main

import "fmt"

var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
}

func main() {
	fmt.Println(l)
}

Output
undefined: l

ローカル変数は、それが割り当てられた関数の外では使用できません。そうしようとすると、コンパイル時にundefinedエラーが発生します。

グローバル変数とローカル変数に同じ変数名を使用する別の例を見てみましょう:

package main

import "fmt"

var num1 = 5

func printNumbers() {
	num1 := 10
	num2 := 7  

	fmt.Println(num1)
	fmt.Println(num2)
}

func main() {
	printNumbers()
	fmt.Println(num1)
}
Output
10 7 5

このプログラムでは、num1変数を2回宣言しました。まず、グローバルスコープでnum1を宣言し、var num1 = 5とし、次にprintNumbers関数のローカルスコープ内で再びnum1 := 10と宣言しました。mainプログラムからnum1を出力すると、値5が出力されます。これは、mainがグローバル変数の宣言のみを認識するためです。しかし、printNumbers関数からnum1を出力すると、ローカル宣言を認識し、値10を出力します。printNumbersは新しい変数num1を作成し、それに10の値を割り当てますが、これは値5のグローバルなnum1インスタンスには影響しません。

変数を扱う際には、プログラムのどの部分が各変数にアクセスする必要があるかも考慮する必要があります。適宜グローバル変数またはローカル変数を採用します。Goプログラム全体を通して、ローカル変数が一般的であることがわかります。

定数

定数は変数に似ていますが、一度宣言されると変更できません。定数は、プログラム内で複数回使用されるが変更されるべきでない値を定義するのに便利です。

例えば、ショッピングカートシステムの税率を宣言したい場合、定数を使用してプログラムの異なる部分で税金を計算することができます。将来的に税率が変更された場合、プログラム内の1箇所の値を変更するだけで済みます。変数を使用した場合、プログラムのどこかで誤って値を変更してしまい、不適切な計算になる可能性があります。

定数を宣言するには、以下の構文を使用できます:

const shark = "Sammy"
fmt.Println(shark)
Output
Sammy

定数を宣言した後に変更しようとすると、コンパイル時エラーが発生します:

Output
cannot assign to shark

定数はuntypedにすることができます。これは整数型データなどの数値を扱う際に便利です。定数がuntypedの場合、明示的に変換されますが、typed定数はそうではありません。定数の使用方法を見てみましょう:

package main

import "fmt"

const (
	year     = 365
	leapYear = int32(366)
)

func main() {
	hours := 24
	minutes := int32(60)
	fmt.Println(hours * year)    
	fmt.Println(minutes * year)   
	fmt.Println(minutes * leapYear)
}
Output
8760 21900 21960

型付きの定数を宣言すると、その型になります。ここで定数leapYearを宣言する際、データ型int32として定義します。したがって、これはtyped定数であり、int32データ型のみで操作できます。型なしで宣言したyear定数は、untypedと見なされます。このため、任意の整数データ型で使用できます。

hoursが定義されたとき、明示的に型を指定しなかったため、型intと推論されました(hours := 24)。minutesを宣言する際、明示的にint32と宣言しました(minutes := int32(60))。

それでは、それぞれの計算がどのように機能するかを見ていきましょう:

hours * year

この場合、hoursint型で、years型なしです。プログラムがコンパイルされるとき、yearsは明示的にint型に変換され、乗算操作が成功します。

minutes * year

この場合、minutesint32型で、year型なしです。プログラムがコンパイルされるとき、yearsは明示的にint32型に変換され、乗算操作が成功します。

minutes * leapYear

この場合、minutesint32型で、leapYear型付きint32型の定数です。両方の変数がすでに同じ型であるため、コンパイラはこの時何もする必要がありません。

もし互換性のない型付きの2つの型を乗算しようとすると、プログラムはコンパイルされません:

fmt.Println(hours * leapYear)
Output
invalid operation: hours * leapYear (mismatched types int and int32)

この場合、hoursint型と推論され、leapYearは明示的にint32型と宣言されています。Goは型付き言語であるため、int型とint32型は数学的な操作に互換性がありません。それらを乗算するためには、一方をint32型またはint型に変換する必要があります。

結論

このチュートリアルでは、Go言語における変数の一般的な使用例についていくつか見てきました。変数はプログラミングの重要な構成要素であり、プログラム内で使用するデータ型の値の代わりとなるシンボルとして機能します。

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-variables-and-constants-in-go