Goのデータ型を理解する
序章
データ型は、プログラムを作成するときに特定の変数が格納する値の種類を指定します。 データ型は、データに対して実行できる操作も決定します。
この記事では、Goに固有の重要なデータ型について説明します。 これはデータ型の徹底的な調査ではありませんが、Goで使用できるオプションを理解するのに役立ちます。 いくつかの基本的なデータ型を理解すると、効率的に実行されるより明確なコードを記述できるようになります。
バックグラウンド
データ型について考える1つの方法は、現実の世界で使用するさまざまな種類のデータを検討することです。 実世界のデータの例は数値です。たとえば、整数(0、1、2、…)、整数(…、-1、0、1、…)、および無理数(π)を使用できます。
通常、数学では、さまざまな種類の数字を組み合わせて、ある種の答えを得ることができます。 たとえば、πに5を追加したい場合があります。
5 + π
無理数を説明するための答えとして方程式を保持するか、πを小数点以下の桁数が省略された数値に丸めてから、数値を合計することができます。
5 + π = 5 + 3.14 = 8.14
しかし、単語などの別のデータ型を使用して数値を評価しようとすると、意味がなくなり始めます。 次の方程式をどのように解きますか?
shark + 8
コンピューターの場合、単語や数字など、各データ型はまったく異なります。 その結果、さまざまなデータ型を使用して値を割り当てる方法と、操作を通じてそれらを操作する方法に注意する必要があります。
整数
数学と同様に、コンピュータープログラミングの整数は、正、負、または0(…、-1、0、1、…)の整数です。 Goでは、整数はint
と呼ばれます。 他のプログラミング言語と同様に、4桁以上のコンマは使用しないでください。したがって、プログラムに1,000を書き込む場合は、1000
と記述してください。
次のような簡単な方法で整数を出力できます。
fmt.Println(-459)
Output-459
または、変数を宣言することもできます。この場合は、次のように、使用または操作している数値の記号です。
var absoluteZero int = -459 fmt.Println(absoluteZero)
Output-459
Goでは整数を使って数学を行うこともできます。 次のコードブロックでは、:=
代入演算子を使用して、変数sum
を宣言およびインスタンス化します。
sum := 116 - 68 fmt.Println(sum)
Output48
出力が示すように、数学演算子-
は、116
から整数68
を減算し、48
になりました。 変数宣言の詳細については、変数のデータ型の宣言セクションを参照してください。
整数は、Goプログラム内でさまざまな方法で使用できます。 Goについて学び続けると、整数を操作し、このデータ型の知識に基づいて構築する多くの機会が得られます。
浮動小数点数
浮動小数点数または浮動小数点数は、整数として表現できない実数を表すために使用されます。 実数にはすべての有理数と無理数が含まれるため、浮動小数点数には9.0や-116.42などの小数部分を含めることができます。 Goプログラムでフロートを考えるために、小数点を含む数値です。
整数の場合と同様に、次のような簡単な方法で浮動小数点数を出力できます。
fmt.Println(-459.67)
Output-459.67
次のように、floatを表す変数を宣言することもできます。
absoluteZero := -459.67 fmt.Println(absoluteZero)
Output-459.67
整数の場合と同様に、Goでもfloatを使用して数学を行うことができます。
var sum = 564.0 + 365.24 fmt.Println(sum)
Output929.24
整数と浮動小数点数の場合、3は整数を表し、3.0は浮動小数点を表すため、3≠3.0であることに注意することが重要です。
数値タイプのサイズ
整数と浮動小数点数の区別に加えて、Goには、サイズの静的または動的な性質によって区別される2種類の数値データがあります。 最初のタイプはアーキテクチャに依存しないタイプです。これは、コードが実行されているマシンに関係なく、ビット単位のデータのサイズが変更されないことを意味します。
今日のほとんどのシステムアーキテクチャは、32ビットまたは64ビットのいずれかです。 たとえば、オペレーティングシステムが64ビットアーキテクチャで実行されている最新のWindowsラップトップ用に開発している場合があります。 ただし、フィットネスウォッチなどのデバイス向けに開発している場合は、32ビットアーキテクチャを使用している可能性があります。 int32
のようなアーキテクチャに依存しない型を使用する場合、コンパイルするアーキテクチャに関係なく、型のサイズは一定になります。
2番目のタイプは、実装固有のタイプです。 このタイプでは、ビットサイズは、プログラムが構築されているアーキテクチャに基づいて変化する可能性があります。 たとえば、int
タイプを使用する場合、Goが32ビットアーキテクチャ用にコンパイルすると、データタイプのサイズは32ビットになります。 プログラムが64ビットアーキテクチャ用にコンパイルされている場合、変数のサイズは64ビットになります。
サイズの異なるデータ型に加えて、整数などの型には、符号付きと符号なしの2つの基本的な型もあります。 int8
は符号付き整数であり、-128から127までの値を持つことができます。 uint8
は符号なし整数であり、0〜255の正の値のみを持つことができます。
範囲はビットサイズに基づいています。 バイナリデータの場合、8ビットは合計256の異なる値を表すことができます。 int
タイプは正の値と負の値の両方をサポートする必要があるため、8ビット整数(int8
)の範囲は-128〜127で、合計256の一意の可能な値になります。
Goには、アーキテクチャに依存しない次の整数型があります。
uint8 unsigned 8-bit integers (0 to 255) uint16 unsigned 16-bit integers (0 to 65535) uint32 unsigned 32-bit integers (0 to 4294967295) uint64 unsigned 64-bit integers (0 to 18446744073709551615) int8 signed 8-bit integers (-128 to 127) int16 signed 16-bit integers (-32768 to 32767) int32 signed 32-bit integers (-2147483648 to 2147483647) int64 signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
浮動小数点数と複素数もさまざまなサイズで提供されます。
float32 IEEE-754 32-bit floating-point numbers float64 IEEE-754 64-bit floating-point numbers complex64 complex numbers with float32 real and imaginary parts complex128 complex numbers with float64 real and imaginary parts
特定のデータ型に有用な名前を割り当てるエイリアス番号タイプもいくつかあります。
byte alias for uint8 rune alias for int32
byte
エイリアスの目的は、プログラムがバイトデータ測定に関係のない小さな整数ではなく、文字列要素の一般的な計算測定としてバイトを使用している場合を明確にすることです。 byte
とuint8
は、プログラムのコンパイル後は同じですが、byte
は文字データを数値形式で表すためによく使用されますが、uint8
はあなたのプログラムの数になりなさい。
rune
エイリアスは少し異なります。 byte
とuint8
がまったく同じデータである場合、rune
は1バイトまたは4バイトで、範囲はint32
によって決定されます。 rune
はUnicode文字を表すために使用されますが、ASCII文字のみがint32
データ型でのみ表すことができます。
さらに、Goには次の実装固有のタイプがあります。
uint unsigned, either 32 or 64 bits int signed, either 32 or 64 bits uintptr unsigned integer large enough to store the uninterpreted bits of a pointer value
実装固有のタイプのサイズは、プログラムがコンパイルされるアーキテクチャによって定義されます。
数値データ型の選択
正しいサイズを選択することは、通常、使用しているデータのサイズよりも、プログラミングしているターゲットアーキテクチャのパフォーマンスに関係があります。 ただし、プログラムのパフォーマンスの具体的な影響を知る必要はなく、最初に開始するときにこれらの基本的なガイドラインのいくつかに従うことができます。
この記事の前半で説明したように、アーキテクチャに依存しないタイプと実装固有のタイプがあります。 整数データの場合、Goでは、int64
またはuint64
の代わりにint
またはuint
のような実装タイプを使用するのが一般的です。 これにより、通常、ターゲットアーキテクチャの処理速度が最速になります。 たとえば、int64
を使用して32ビットアーキテクチャにコンパイルする場合、アーキテクチャ間でデータを移動するために追加のCPUサイクルが必要になるのと比べて、これらの値の処理には少なくとも2倍の時間がかかります。 代わりにint
を使用した場合、プログラムはそれを32ビットアーキテクチャの32ビットサイズとして定義し、処理が大幅に高速化されます。
特定のサイズ範囲を超えないことがわかっている場合は、アーキテクチャに依存しないタイプを選択すると、速度が向上し、メモリ使用量が減少する可能性があります。 たとえば、データが100
の値を超えず、正の数のみになることがわかっている場合、uint8
を選択すると、必要なデータが少なくなるため、プログラムがより効率的になります。メモリー。
数値データ型の可能な範囲のいくつかを見てきたので、プログラムでそれらの範囲を超えた場合に何が起こるかを見てみましょう。
オーバーフロー対。 包み込む
Goは、値がで計算されるかどうかに応じて、格納するように設計されたデータ型よりも大きい値を格納しようとすると、数値のオーバーフローと数値のラップアラウンドの両方を行う可能性があります。コンパイル時または実行時。 コンパイル時エラーは、プログラムがプログラムをビルドしようとしたときにエラーを検出したときに発生します。 プログラムのコンパイル後、実際に実行中にランタイムエラーが発生します。
次の例では、maxUint32
を最大値に設定します。
package main import "fmt" func main() { var maxUint32 uint32 = 4294967295 // Max uint32 size fmt.Println(maxUint32) }
コンパイルして実行すると、次の結果が得られます。
Output4294967295
実行時に値に1
を追加すると、0
にラップアラウンドします。
Output0
一方、コンパイル時の前に、変数を割り当てるときに1
を変数に追加するようにプログラムを変更しましょう。
package main import "fmt" func main() { var maxUint32 uint32 = 4294967295 + 1 fmt.Println(maxUint32) }
コンパイル時に、コンパイラが値が大きすぎて指定されたデータ型を保持できないと判断できる場合、overflow
エラーがスローされます。 これは、計算された値が指定したデータ型に対して大きすぎることを意味します。
コンパイラは値をオーバーフローさせると判断できるため、エラーがスローされます。
Outputprog.go:6:36: constant 4294967296 overflows uint32
データの境界を理解することは、将来のプログラムの潜在的なバグを回避するのに役立ちます。
数値型について説明したので、ブール値を格納する方法を見てみましょう。
ブール値
boolean データ型は、true
またはfalse
の2つの値のいずれかになり、データ型として宣言する場合はbool
として定義されます。 ブール値は、数学の論理ブランチに関連付けられている真理値を表すために使用されます。これは、コンピューターサイエンスのアルゴリズムに情報を提供します。
値true
およびfalse
は、Goで事前に宣言された識別子であるため、常にそれぞれ小文字のt
およびf
になります。
数学の多くの演算は、真または偽のいずれかに評価される答えを私たちに与えます。
- 未満
- 等しい
数値と同様に、ブール値を変数に格納できます。
myBool := 5 > 8
次に、fmt.Println()
関数を呼び出して、ブール値を出力できます。
fmt.Println(myBool)
5
は8
より大きくないため、次の出力が返されます。
Outputfalse
Goでより多くのプログラムを作成するにつれて、ブール値がどのように機能するか、およびtrue
またはfalse
のいずれかに評価されるさまざまな関数および操作がプログラムのコースをどのように変更できるかを理解するようになります。
文字列
文字列は、定数または変数のいずれかである1つ以上の文字(文字、数字、記号)のシーケンスです。 文字列は、Goの逆引用符`
または二重引用符"
内に存在し、使用する引用符によって異なる特性を持ちます。
逆引用符を使用すると、raw文字列リテラルが作成されます。 二重引用符を使用すると、解釈された文字列リテラルが作成されます。
生の文字列リテラル
生の文字列リテラルは、バッククォート間の文字シーケンスであり、バックティックと呼ばれることがよくあります。 引用符内では、後引用符自体を除いて、すべての文字が後引用符の間に表示されるのと同じように表示されます。
a := `Say "hello" to Go!` fmt.Println(a)
OutputSay "hello" to Go!
通常、バックスラッシュは文字列内の特殊文字を表すために使用されます。 たとえば、解釈された文字列では、\n
は文字列の改行を表します。 ただし、バックスラッシュは生の文字列リテラル内では特別な意味はありません。
a := `Say "hello" to Go!\n` fmt.Println(a)
バックスラッシュは文字列リテラルでは特別な意味を持たないため、新しい行を作成する代わりに、実際には\n
の値を出力します。
OutputSay "hello" to Go!\n
生の文字列リテラルを使用して、複数行の文字列を作成することもできます。
a := `This string is on multiple lines within a single back quote on either side.` fmt.Println(a)
OutputThis string is on multiple lines within a single back quote on either side.
上記のコードブロックでは、新しい行は文字通り入力から出力に引き継がれていました。
解釈された文字列リテラル
解釈される文字列リテラルは、"bar"
のように、二重引用符で囲まれた文字シーケンスです。 引用符内には、改行とエスケープされていない二重引用符を除く任意の文字が表示される場合があります。 解釈された文字列に二重引用符を表示するには、次のようにバックスラッシュをエスケープ文字として使用できます。
a := "Say \"hello\" to Go!" fmt.Println(a)
OutputSay "hello" to Go!
ほとんどの場合、解釈された文字列リテラルを使用します。これは、文字列内でエスケープ文字を使用できるためです。 文字列の操作の詳細については、Goでの文字列の操作の概要をご覧ください。
UTF-8文字を含む文字列
UTF-8は、可変幅の文字を1〜4バイトにエンコードするために使用されるエンコード方式です。 Goは、特別なセットアップ、ライブラリ、またはパッケージなしで、すぐに使用できるUTF-8文字をサポートします。 文字A
などのローマ字は、数値65などのASCII値で表すことができます。 ただし、世
の国際文字などの特殊文字では、UTF-8が必要になります。 Goは、UTF-8データにrune
エイリアスタイプを使用します。
a := "Hello, 世界"
for
ループでrange
キーワードを使用して、UTF-8文字列を含むGoの任意の文字列にインデックスを付けることができます。 for
ループとrange
については、シリーズの後半で詳しく説明します。 今のところ、これを使用して特定の文字列のバイト数をカウントできることを知っておくことが重要です。
package main import "fmt" func main() { a := "Hello, 世界" for i, c := range a { fmt.Printf("%d: %s\n", i, string(c)) } fmt.Println("length of 'Hello, 世界': ", len(a)) }
上記のコードブロックでは、変数a
を宣言し、それにHello, 世界
の値を割り当てました。 割り当てられたテキストには、UTF-8文字が含まれています。
次に、標準のfor
ループとrange
キーワードを使用しました。 Goでは、range
キーワードは、一度に1文字を返す文字列と、その文字が文字列内にあるバイトインデックスを介してインデックスを作成します。
fmt.Printf
関数を使用して、%d: %s\n
のフォーマット文字列を提供しました。 %d
は数字(この場合は整数)の印刷動詞であり、%s
は文字列の印刷動詞です。 次に、for
ループの現在のインデックスであるi
と、for
ループの現在の文字であるc
の値を提供しました。 。
最後に、組み込みのlen
関数を使用して、変数a
の全長を出力しました。
前に、ルーンはint32
のエイリアスであり、1〜4バイトで構成できることを説明しました。 世
文字の定義には3バイトかかり、UTF-8文字列を介して範囲を指定すると、それに応じてインデックスが移動します。 これが、i
が印刷時にシーケンシャルではない理由です。
Output0: H 1: e 2: l 3: l 4: o 5: , 6: 7: 世 10: 界 length of 'Hello, 世界': 13
ご覧のとおり、長さは文字列全体に及ぶのにかかった回数よりも長くなっています。
常にUTF-8文字列を使用しているとは限りませんが、使用している場合は、それらが単一のint32
ではなくルーン文字である理由を理解できます。
変数のデータ型の宣言
さまざまなプリミティブデータ型について理解したので、これらの型をGoの変数に割り当てる方法について説明します。
Goでは、キーワードvar
の後に変数の名前と必要なデータ型を指定して、変数を定義できます。
次の例では、タイプfloat64
のpi
という変数を宣言します。
キーワードvar
は、最初に宣言されたものです。
var pi float64
変数の名前pi
が続きます。
var pi float64
そして最後にデータ型float64
:
var pi float64
オプションで、3.14
などの初期値も指定できます。
var pi float64 = 3.14
Goは静的に型付けされた言語です。 静的に型付けされるということは、プログラム内の各ステートメントがコンパイル時にチェックされることを意味します。 また、データ型が変数にバインドされているのに対し、動的にリンクされた言語では、データ型が値にバインドされていることも意味します。
たとえば、Goでは、変数を宣言するときに型が宣言されます。
var pi float64 = 3.14 var week int = 7
これらの変数を異なる方法で宣言した場合、これらの各変数は異なるデータ型になる可能性があります。
これは、データ型が値に関連付けられているPHPのような言語とは異なります。
$s = "sammy"; // $s is automatically a string $s = 123; // $s is automatically an integer
上記のコードブロックでは、最初の$s
は値"sammy"
が割り当てられているため文字列であり、2番目は値123
があるため整数です。
次に、配列などのより複雑なデータ型を見てみましょう。
配列
array は、要素の順序付けられたシーケンスです。 アレイの容量は、作成時に定義されます。 配列がそのサイズを割り当てると、サイズは変更できなくなります。 配列のサイズは静的であるため、メモリを1回だけ割り当てることを意味します。 これにより、配列の操作が多少難しくなりますが、プログラムのパフォーマンスが向上します。 このため、配列は通常、プログラムを最適化するときに使用されます。 次に説明するスライスは、より柔軟性があり、他の言語の配列と考えるものを構成します。
配列は、配列のサイズを宣言し、次に中括弧{ }
で定義された値を持つデータ型を宣言することによって定義されます。
文字列の配列は次のようになります。
[3]string{"blue coral", "staghorn coral", "pillar coral"}
配列を変数に格納して出力できます。
coral := [3]string{"blue coral", "staghorn coral", "pillar coral"} fmt.Println(coral)
Output[blue coral staghorn coral pillar coral]
前述のように、スライスは配列に似ていますが、はるかに柔軟性があります。 この可変データ型を見てみましょう。
スライス
スライスは、長さが変化する可能性のある要素の順序付けられたシーケンスです。 スライスは動的にサイズを大きくすることができます。 スライスに新しいアイテムを追加するときに、スライスに新しいアイテムを格納するのに十分なメモリがない場合、必要に応じてシステムからより多くのメモリを要求します。 スライスは必要に応じて要素を追加するために拡張できるため、配列よりも一般的に使用されます。
スライスは、開始および終了の角括弧[]
が前に付いたデータ型を宣言し、中括弧{ }
の間に値を持つことによって定義されます。
整数のスライスは次のようになります。
[]int{-3, -2, -1, 0, 1, 2, 3}
フロートのスライスは次のようになります。
[]float64{3.14, 9.23, 111.11, 312.12, 1.05}
文字列のスライスは次のようになります。
[]string{"shark", "cuttlefish", "squid", "mantis shrimp"}
文字列のスライスをseaCreatures
として定義しましょう。
seaCreatures := []string{"shark", "cuttlefish", "squid", "mantis shrimp"}
変数を呼び出すことで、それらを出力できます。
fmt.Println(seaCreatures)
出力は、作成したリストとまったく同じになります。
Output[shark cuttlefish squid mantis shrimp]
append
キーワードを使用して、スライスにアイテムを追加できます。 次のコマンドは、seahorse
の文字列値をスライスに追加します。
seaCreatures = append(seaCreatures, "seahorse")
印刷することで、追加されたことを確認できます。
fmt.Println(seaCreatures)
Output[shark cuttlefish squid mantis shrimp seahorse]
ご覧のとおり、未知のサイズの要素を管理する必要がある場合、スライスは配列よりもはるかに用途が広いでしょう。
マップ
map は、Goの組み込みハッシュまたは辞書タイプです。 マップは、キーと値をペアとして使用してデータを保存します。 これは、インデックス(この場合はキー)で値をすばやく検索するプログラミングに役立ちます。 たとえば、ユーザーIDで索引付けされたユーザーのマップを保持したい場合があります。 キーはユーザーIDであり、ユーザーオブジェクトは値です。 マップは、キーワードmap
、角かっこ[ ]
のキーデータ型、中括弧内の値データ型とキー値のペアを使用して作成されます。
map[key]value{}
通常、IDに含まれる情報など、関連するデータを保持するために使用されるマップは、次のようになります。
map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
中括弧に加えて、マップ全体にコロンもあります。 コロンの左側の単語がキーです。 キーは、Goの比較可能なタイプであればどれでもかまいません。 比較可能なタイプは、strings
、ints
などのプリミティブタイプです。 プリミティブ型は言語によって定義され、他の型を組み合わせて構築されたものではありません。 これらはユーザー定義の型にすることができますが、プログラミングエラーを回避するために、単純に保つことをお勧めします。 上記の辞書のキーは、name
、animal
、color
、およびlocation
です。
コロンの右側の単語は値です。 値は任意のデータ型で構成できます。 上記の辞書の値は、Sammy
、shark
、blue
、およびocean
です。
マップを変数内に保存して印刷してみましょう。
sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"} fmt.Println(sammy)
Outputmap[animal:shark color:blue location:ocean name:Sammy]
サミーの色を分離したい場合は、sammy["color"]
を呼び出すことで分離できます。 それを印刷してみましょう:
fmt.Println(sammy["color"])
Outputblue
マップはデータを保存するためのキーと値のペアを提供するため、Goプログラムの重要な要素になる可能性があります。
結論
この時点で、Goで使用できる主要なデータ型のいくつかをよりよく理解する必要があります。 Go言語でプログラミングプロジェクトを開発する場合、これらの各データ型が重要になります。
Goで利用できるデータ型をしっかりと把握したら、状況に応じてデータ型を変更するためのデータ型の変換方法を学ぶことができます。