「Go/変数」の版間の差分
削除された内容 追加された内容
→小数以外のビット精度: 低精度整数型の用途 タグ: 2017年版ソースエディター |
s/予約語/キーワード/、{{Cite book}} タグ: 2017年版ソースエディター |
||
1 行
変数宣言では、1つまたは複数の変数を作成し、対応する識別子を結合し、それぞれに型と初期値を与えます<ref name="Declarations_and_scope">{{cite book
| url = https://golang.org/ref/spec#Declarations_and_scope
| title = The Go Programming Language Specification
| chapter = Declarations_and scope ¶
| date = Jul 26, 2021
| publisher = The Go website
}}</ref>。
;構文:<syntaxhighlight lang="ebnf">
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) ;
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) ;
</syntaxhighlight>
==== 初期化と型推論 ====
Go言語では、変数宣言の初期値から宣言される変数の型を推論します。
;[https://paiza.io/projects/CaES_qcOAYx229wAJi6YZw?language=go コード例]:<syntaxhighlight lang="go" highlight="6,7" line>
package main
import "fmt"
func main() {
var n = 5
fmt.Printf("var n = 5 => 値:%v 型:%T\n", n, n)
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
var n = 5 => 値:5 型:int
</syntaxhighlight>
;解説:<syntaxhighlight lang="go" start=6 line>
var n = 5
</syntaxhighlight>
で変数 <var>n</var> を初期値を 5 で宣言しています。
明示的に型を伴って宣言していませんが、初期値の 5 から int が型推定されます。
;fmt.Printf:<syntaxhighlight lang="go" start=7 line>
fmt.Printf("var n = 5 => 値:%v 型:%T\n", n, n)
</syntaxhighlight>
fmtパッケージのPrintf関数を使って表示しています。
名前から予想がつく通り、[[C言語]]の標準ライブラリー関数の printf() に習った関数ですが、Go言語の慣習に従って関数名の最初だけ大文字です。
機能的にも、C言語のprintfにはない型指定子 %v(式の値に自然な形式で表示する)と %T(式の型を表示する)の様な拡張が施されています。
=== 初期化を伴わない例 ===
;[https://paiza.io/projects/kl8iW9-vUfuAVWaOMxl8cg?language=go コード例]:<syntaxhighlight lang="go" highlight=6 line>
package main
import "fmt"
func main() {
var n int
fmt.Printf("var n int => 値:%v 型:%T\n", n, n)
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
var n int => 値:0 型:int
</syntaxhighlight>
;解説:<syntaxhighlight lang="go" start=6 line>
var n int
</syntaxhighlight>
で int 型の変数 <var>n</var> を初期値なしで宣言しています。
この例は初期値が与えられていないので、明示的に型を指定する必要があります。
この例では変数の値は 0 でしたが、型により暗黙で推定される値が異なるので、初期値を与え型を推定させるスタイルが好まれます。
=== 短い変数宣言 ===
変数宣言にはもう1つの構文があります。
;短い変数宣言:短い変数宣言は、以下の構文を使用します。
;構文:<syntaxhighlight lang="ebnf">
ShortVarDecl = IdentifierList ":=" ExpressionList ;
</syntaxhighlight>
これは、初期化式を持つが型を持たない通常の変数宣言の短縮形です。
;[https://paiza.io/projects/Aedbpc_Oo9V-jxM9dMBFNw?language=go コード例]:<syntaxhighlight lang="go" highlight=6 line>
package main
import "fmt"
func main() {
n := 5
fmt.Printf("var n = 5 => 値:%v 型:%T\n", n, n)
}
</syntaxhighlight>
;実行結果:(略)
;解説:<syntaxhighlight lang="go" start=6 line>
n := 5
</syntaxhighlight>
同じ様に、int 型の変数 <var>n</var> を初期値を 5 で宣言しています。
var を伴った宣言と異なり、初期値は省略できません。
短い変数宣言は、if文、switch文やfor文に「文スコープな変数」を宣言する時に使われます。<!--条件分岐と繰り返しにリンクしたいが、文スコープな変数への言及がまだない -->
=== 複数の変数の一括宣言 ===
;構文:<syntaxhighlight lang="ebnf">
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) ;
</syntaxhighlight>
の後半 <code>"(" { VarSpec ";" } ")" </code>は、宣言子の繰り返しを表しています。
;[https://paiza.io/projects/cWIqw1qXXju4W-8eZ2GZ0g?language=go コード例]:<syntaxhighlight lang="go" highlight=6 line>
<syntaxhighlight lang="go">
package main
113 ⟶ 100行目:
var (
name string
number int
}{
{ "abc", 1 },
{ "def", 2 },
{ "ghi", 3 },
{ "xyz", 9 },
};
f = 3.14
)
func main() {
fmt.
fmt.Printf("b: 値:%v 型:%T\n", b, b)
fmt.Printf("v: 値:%v 型:%T\n", v, v)
fmt.Printf("f: 値:%v 型:%T\n", f, f)
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
a: 値:100 型:int
b: 値:string 型:string
v: 値:[{abc 1} {def 2} {ghi 3} {xyz 9}] 型:[]struct { name string; number int }
f: 値:3.14 型:float64
</syntaxhighlight>
a,bそれにfはある程度予想が着くと思います。
vは匿名構造体配列の複合リテラルです。<!--リテラルについては単独で立項するべき?-->
この様に fmt.Printf の %v ならびに %T 型指定子は、ユーザー定義を含め任意のオブジェクトの値と型を表示できるので便利です。
== 整数と浮動小数点数 ==
上記の例のように、浮動小数点数リテラルの型は float64 です。この他に float32 という型もありますが、 float という型はありません。
異なる数値型の間の演算はエラーにはならず、昇格則が働きます。
{{See also|Go/算術演算と数学関数}}
=== 小数以外のビット精度 ===
浮動小数点数型以外に整数型 int にも、ビット幅を伴った、<code>int32</code>, <code>int64</code> や<code>int8</code>, <code>int16</code> があります。
このような低精度の整数型にはニーズがないと、感じることがあるかもしれないが回帰型ニューラルネットワークなどの人工知能応用では精度は必ずしも必要なく、メモリーフットプリントの削減と計算時間の削減という意味で今後もニーズがあります。
{|class="wikitable"
226 ⟶ 167行目:
int型には
型指定で単に「int」だけ入力したときに作成される整数は
なので、符号ありの整数では、intの前に、なんの接頭辞もつけ
uint64 などの頭文字「u」は、unsigned (符号なし、「アンサインド」と読む)の
特別な事情のないかぎり、整数型の指定のときには「int」とだけ入力しておけば、Go言語コンパイラが、アーキテクチャにもとづき、自動でビット精度を判断してくれますので、なるべく「int」とだけ入力してコンパイラに任せておくのが簡便でしょう。
====
キーワード var を使って宣言した場合も、 簡略表記「:=」を使った場合にも関数の中で宣言された変数のスコープは関数のブロックです(関数の中のfor文やif文で宣言された場合は文スコープになります)。
また簡略表記「:=」はグローバル変数の宣言には使えません。
なお、この「:=」演算子は、情報科学では一般に「定義」(ていぎ)と言われますが、しかしGo言語の場合、この演算子の内容は定義ではなく、単にローカル変数を宣言しているだけです。
==== 文字列型 ====
文字列変数を使うには、
単に、代入した文字列を二重引用符 " " でククるだけです。
なお、C++にはstring型はなく標準テンプレートクラスライブラリーの string クラスを使います。JavaScriptには文字列プリミティブとStringオブジェクトがあります(なお標準C言語にはstring型が無く、'\0'で終端されたchar型の配列で表現していますが、文字列の連結などは標準ライブラリの関数となっており、結果を表すバッファのサイズなどへの責任はプログラマ本人が負い。このことが度々バッファオーバープロー等を引き起こし脆弱性の原因となっています。)。
==== キーワード ====
以下のキーワードは予約済みで、識別子として使用することはできません<ref name="Keywords">{{cite book
| url = https://golang.org/ref/spec#Keywords
| title = The Go Programming Language Specification
| chapter = Keywords ¶
| date = Jul 26, 2021
| publisher = The Go website
}}</ref>。
;Goのキーワード一覧:<source lang="text">
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
</source>
'''int''' や '''float32''' などの(プリミティブな)型名が含まれていません。
このため、<source lang=go inline>var int = 123.456 </source>は、float64型の変数 int 値は 123.456 と「正しく」解釈されます。
PL/Iのようですね。
== 型変換 ==
変換は,式の型を変換によって指定された型に変更します。変換は,ソースの中で文字通りに現れるかもしれませんし,式が現れる文脈によって暗示されるかもしれません。
明示的な変換は,T(x)という形式の式で,Tは型であり,xはT型に変換できる式である<ref name="Conversions ">{{cite book
| url = https://golang.org/ref/spec#Conversions
| title = The Go Programming Language Specification
| chapter = Conversions ¶
| date = Jul 26, 2021
| publisher = The Go website
}}</ref>。
;構文:<syntaxhighlight lang="ebnf">
Conversion = Type "(" Expression [ "," ] ")" .
</syntaxhighlight>
Go言語は静的型システムを導入しており、この意味ではC言語に近く型を厳密に扱います(といってもIntegerとRealの足し算ですら明示的な型変換が必要なPascal程ではありません)。
JavaScriptやRubyなどの動的な型システムを採用したシステムは、「数値型に文字列型を足す」、「文字列を1進める」などの異なる型同士の演算に於いて暗黙の型変換が行われます。
Go言語では、どうしても異なる型どうしの複数個の変数を足しあわせる処理などを場合、どちらかの変数の型を変換し、相手ガワの変数の型に合わせるという、型の変換をする必要があります。
=== 数値どうしの型変換 ===
整数型で宣言した数を浮動小数型にしたり、float32型で宣言した数をfloat64型に変換するには、
;[https://paiza.io/projects/puE2WlQcQ4xZEQFRh2SZlg?language=go コード例]:<syntaxhighlight lang="go" line>
package main
import "fmt"
func main() {
fmt.Println("i = ", i)
fmt.Println("i / 3 = ", i / 3)
fmt.Println("
fmt.Println("f / 3 = ", f / 3)
}
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
i = 8
i / 3 = 2
f / 3 = 2.6666666666666665
</syntaxhighlight>
やや直感的ではありませんが、キーワード var を使った変数宣言で型名を明示した場合の初期値には暗黙の型変換は起こりません。
:<syntaxhighlight lang="go" start=10line>
f := float64(i)
</syntaxhighlight>
は
:<syntaxhighlight lang="go" start=10 line>
var f float64 = i
</syntaxhighlight>
;コンパイルエラー:<syntaxhighlight lang="text">
# command-line-arguments
./Main.go:10:9: cannot use i (type int) as type float64 in assignment
</syntaxhighlight>
ではなく
:<syntaxhighlight lang="go" start=10 line>
var f float64 = float64(i)
</syntaxhighlight>
とする必要があります。
ちなみに C言語の感覚で、
:<syntaxhighlight lang="go" start=10 line>
f := 1.0 * i
</syntaxhighlight>
とすると f の型は(float64 ではなく)int です。
== 脚註 ==
<references />
|