Go は、静的型付けされコンパイルされる高水準の汎用プログラミング言語です。構文のシンプルさと、一般的なプロジェクトの多くのニーズを満たす大規模な標準ライブラリが含まれていることによる開発効率の高さで知られています。[ 13 ] 2007 年にGoogle [ 14 ]でRobert Griesemer、Rob Pike、Ken Thompsonによって設計され、2009 年 11 月に一般公開されました。 [ 4 ]構文的にはCに似ていますが、ガベージ コレクション、構造型付け[ 8 ]、CSPスタイルの並行処理も備えています。[ 15 ]曖昧さを避けるため、また以前のドメイン名のため、Golangと呼ばれることが多いですが、正式名称は Go です。[ 16 ]golang.org
主な実装方法は2つあります。
サードパーティ製のソース間コンパイラであるGopherJS [ 22 ]は、フロントエンドWeb開発のためにGoをJavaScriptにトランスパイルします。
Go は、マルチコア、ネットワークマシン、大規模なコードベースの時代におけるプログラミングの生産性を向上させるために、2007 年にGoogleで設計されました。[ 23 ]設計者たちは、Google で使用されている他の言語に対する批判に対処しつつ、それらの有用な特性を維持したいと考えていました。[ 24 ]
その設計者たちは主に、C++に対する共通の嫌悪感に突き動かされていた。[ 26 ] [ 27 ] [ 28 ]
Go は 2009 年 11 月に一般公開され[ 29 ]、バージョン 1.0 は 2012 年 3 月にリリースされました[ 30 ] [ 31 ]。Goは Google [ 32 ]や他の多くの組織やオープンソース プロジェクトで広く使用されています。
振り返ってみると、Goの開発者たちは、Goが成功した理由として、言語の並行処理機能に対するランタイムサポートを含む、言語を取り巻く全体的なエンジニアリング作業を挙げている。
ほとんどの言語の設計は構文、意味論、型付けの革新に重点を置いているが、Go はソフトウェア開発プロセスそのものに焦点を当てている。... 言語自体の主要な特異な特性である並行性は、2010 年代のマルチコア CPU の普及に伴って発生した問題に対処した。しかし、より重要なのは、パッケージング、依存関係、ビルド、テスト、デプロイ、およびソフトウェア開発の世界におけるその他の日常的なタスクの基礎を確立した初期の作業であり、これらは通常、言語設計において最優先事項ではない側面である。[ 33 ]

ゴーファーのマスコットは、2009年に言語のオープンソース化に合わせて導入されました。Plan 9のウサギのマスコットをデザインしたレネー・フレンチは、以前のWFMUのTシャツのデザインからゴーファーを改変しました。 [ 34 ]ゴーファーは当初ゴードンという名前でしたが、[ 14 ] [ a ] 2010年以降は名前がありません。 [ 34 ] [ 35 ]
2016 年 11 月、Go と Go Mono フォントが、タイプ デザイナーのCharles BigelowとKris HolmesによってGo プロジェクトでの使用のためにリリースされました。Go はLucida Grandeに似たヒューマニスト サンセリフですが、 HelveticaとArialとほぼ (完全ではない) メトリック互換性があり、Go Mono は等幅フォントです。どちらのフォントもWGL4文字セットに準拠しており、大きなx ハイトと明確な文字形状で読みやすいように設計されています。Go と Go Mono はどちらも、スラッシュ付きのゼロ、テール付きの小文字、セリフ付きの大文字を持つことでDIN 1450 規格に準拠しています。 [ 36 ] [ 37 ]lI
2018年4月、ブランドデザイナーのアダム・スミスによってオリジナルのロゴが再デザインされました。新しいロゴは、右に傾いたモダンでスタイリッシュな「GO」に、流れるような線が描かれています。ゴーファーのマスコットは変更されていません。[ 38 ]
Goの初期バージョンにおけるジェネリックプログラミングのサポートの欠如は、かなりの批判を招いた。 [ 39 ]設計者たちはジェネリックプログラミングに対してオープンな姿勢を示し、組み込み関数は実際には型ジェネリックであるが、特別なケースとして扱われていると指摘した。パイクはこのことを、いずれ変更されるかもしれない弱点と呼んだ。[ 40 ] Googleチームはジェネリクスを備えた実験的なGo方言用のコンパイラを少なくとも1つ構築したが、リリースしなかった。[ 41 ]
2018年8月、Goの主要貢献者たちは、汎用プログラミングとエラー処理の設計案を公開し、ユーザーにフィードバックを求めた。[ 42 ] [ 43 ]しかし、エラー処理の提案は最終的に放棄された。[ 44 ]
2020年6月、ジェネリック関数と型を宣言するために必要な構文をGoに追加する新しい設計文書の草案[ 45 ]が公開されました。ユーザーが新しい構文を試せるように、コード変換ツールgo2goと、ジェネリクス対応のオンラインGo Playgroundバージョンが提供されました。[ 46 ]
ジェネリクスは、2022年3月15日のバージョン1.18でついにGoに追加されました。[ 47 ]
Go 1 は、言語仕様と標準ライブラリの主要部分との互換性を保証しています[ 48 ] 。現在の Go 1.26 リリース[ 49 ]までのすべてのバージョンで、この約束が守られてきました。
Go はgo1.[major].[patch]、 のようなバージョン形式を使用し、go1.26.0各メジャー Go リリースは、2 つの新しいメジャーリリースが出るまでサポートされます。ほとんどのソフトウェアとは異なり、Go ではバージョンの 2 番目の数字をメジャーバージョンと呼びます。つまり、 の はgo1.26.0メジャー26バージョンです。[ 50 ]これは、Go が 2.0 に到達することは決してなく、潜在的な破壊的変更よりも後方互換性を優先するためです。[ 51 ]
Go言語はC言語(特にPlan 9方言[ 52 ] )の影響を受けていますが、よりシンプルさと安全性を重視しています。Go言語は以下の要素で構成されています。
selectステートメントGoの構文には、コードを簡潔かつ読みやすくするためにCから変更された点がいくつかあります。宣言と初期化を組み合わせた演算子が導入され、プログラマは変数の型を指定せずに`:`や` : `と記述できるようになりました。これはCの`:`や`:`とは対照的です(ただし、C23以降はC++と同様に`:`を使用して型推論がサポートされています)。また、Goではステートメント条件で括弧を使用する必要もなくなりました。i:=3s:="Hello, world!"inti=3;char*s="Hello, world!";autoif
セミコロンは依然として文を終了させますが、[ b ]行末の場合は暗黙的に終了します。[ c ]
メソッドは複数の値を返すことができ、ペアを返すことは、Go でメソッドが呼び出し元にエラーを示す慣習的な方法です。[ d ] Go は、構造体パラメータを名前で初期化したり、マップやスライスを初期化したりするためのリテラル構文を追加しました。C の 3 つのステートメントのループの代替として、Go の式を使用すると、配列、スライス、文字列、マップ、チャネルを簡潔に反復できます。[ 60 ]result,errforrange
Goには以下の25個のキーワードが含まれています: [ 61 ]
breakcasechanconstcontinuedefaultdeferelsefallthroughforfuncgogotoifimportinterfacemappackagerangereturnselectstructswitchtypevarbyteGo には、数値型 ( 、int64、float32など)、ブール値、バイト列 ( )など、多くの組み込み型がありますstring。文字列は不変です。組み込み演算子とキーワード (関数ではなく) により、連結、比較、UTF-8エンコード/デコードが提供されます。[ 62 ]レコード型はキーワードで定義できますstruct。[ 63 ]
Goには以下のプリミティブが含まれています: [ 64 ]
boolint8uint8int16uint16int32uint32int64uint64intuintuintptrfloat32float64complex64complex128stringbyteは のエイリアスでありuint8、runeは のエイリアスであることに注意してくださいint32。
各型Tと各非負整数定数に対してn、配列型が で表されます[n]T。したがって、長さの異なる配列は異なる型になります。動的配列は「スライス」として利用でき、[]Tある型に対して で表されますT(C/C++ やJavaなどの他の言語と比較してください。これらの言語では、配列は で表されますT[])。これらには長さと容量があり、配列を拡張するために新しいメモリを割り当てる必要があるタイミングを指定します。複数のスライスが基となるメモリを共有できます。[ 40 ] [ 65 ] [ 66 ]
ポインタはすべての型で使用可能で、型へのポインタTは で表されます( Rust*Tと同様ポインタが で表されるC/C++ やC#などの他の言語と比較してください)。アドレス取得と間接参照はand演算子を使用するか、メソッド呼び出しまたは属性アクセス構文を通じて暗黙的に行われます。 [ 67 ] [ 68 ]標準ライブラリの特殊型を介する場合を除き、ポインタ演算はありません。 [ e ] [ 69 ]T*&*unsafe.Pointer
K型、のペアに対してV、 型は型キーを型値にmap[K]Vマッピングする型であり、他の言語のと同等と考えることができます。Go プログラミング言語仕様では、マップ型のパフォーマンス保証や実装要件は規定されていませんが、通常はハッシュテーブル(他の言語の と同等) として実装されます。ハッシュテーブルは、特別な構文と組み込み関数を備え、言語に組み込まれています。は、同時実行中の Go プロセス間で型の値を送信できるチャネルです。[ 70 ]KVMap<K, V>HashMap<K, V>chan TT
Go の型システムは、インターフェースのサポートを除けば名目型です。typeキーワードを使用して、同じレイアウト ( の場合、同じメンバーが同じ順序) を持つ他の名前付き型とは異なる新しい名前付き型structを定義できます。型間の変換 (たとえば、さまざまな整数型間) は事前に定義されており、新しい型を追加すると追加の変換を定義できますが、名前付き型間の変換は常に明示的に呼び出す必要があります。[ 71 ]たとえば、キーワードを使用して、32 ビット符号なし整数に基づくIPv4typeアドレスの型を次のように定義できます。
タイプipv4addr uint32この型定義では、値をIPアドレスとしてipv4addr(x)解釈します。単に型の変数に代入すると、型エラーになります。[ 72 ]uint32xxipv4addr
定数式は型付きまたは「型なし」のいずれかになります。定数式は、それが表す値がコンパイル時のチェックを通過する場合に、型付き変数に代入されるときに型が与えられます。[ 73 ]
関数型はキーワードで示されます。関数型は、0 個以上のパラメータfuncを受け取り、0 個以上の値を返します。これらの値はすべて型付けされています。パラメータと戻り値によって関数型が決まります。したがって、は、と 32 ビット符号付き整数を受け取り、符号付き整数 (デフォルト幅) と組み込みインターフェース型の値を返す関数の型です。 [ 74 ]func(string, int32) (int, error)stringerror
名前付き型には、それぞれ関連付けられたメソッドセットがあります。上記のIPアドレスの例は、その値が既知の標準であるかどうかを確認するメソッドを追加することで拡張できます。
// ZeroBroadcast は、addr が 255.255.255.255 であるかどうかを報告します。func ( addr ipv4addr ) ZeroBroadcast () bool { return addr == 0xFFFFFFFF }名目上の型付けのため、このメソッド定義は にメソッドを追加しますipv4addrが、 には追加しませんuint32。メソッドには特別な定義と呼び出し構文がありますが、明確なメソッド型はありません。[ 75 ]
Go は、クラス継承に代わる 2 つの機能を提供します。
1つ目は埋め込みで、これは自動化された合成の一形態と見なすことができる。[ 76 ]
2つ目は、実行時多態性を提供するインターフェースです。[ 77 ] : 266インターフェースは型のクラスであり、Go の名目上の型システムにおいて限定的な構造型付けを提供します。インターフェース型のオブジェクトは、C++オブジェクトが基底クラスと派生クラスの両方に同時に属するのと同様に、別の型にも属します。Go インターフェースの設計は、Smalltalk プログラミング言語のプロトコルに触発されました。 [ 78 ]複数の情報源が、Go インターフェースを説明する際にダックタイピングという用語を使用しています。 [ 79 ] [ 80 ]ダックタイピングという用語は厳密には定義されていないため間違いではありませんが、通常は型の適合性が静的にチェックされないことを意味します。Go コンパイラは (型アサーションを実行する場合を除いて) Go インターフェースへの適合性を静的にチェックするため、Go の作者は構造型付けという用語を好みます。[ 81 ]
インターフェース型の定義では、必要なメソッドが名前と型で列挙されます。インターフェース型 I の必要なメソッドすべてに一致する関数が存在する型 T のオブジェクトは、型 I のオブジェクトでもあります。型 T の定義では、型 I を識別する必要はありません (また、識別できません)。たとえば、、、ShapeおよびSquareがCircle次のように定義されている場合
import "math"type Shape interface { Area () float64 }// 注: "implements" 宣言はありませんtype Square struct { side float64 }func ( sq Square ) Area ( ) float64 { return sq.side * sq.side }// ここにも「implements」宣言はありませんtype Circle struct { radius float64 }func ( c Circle ) Area ( ) float64 { return math.Pi * math.Pow ( c.radius , 2 ) }すると、aSquareと a の両方Circleが暗黙的に a となりShape、 - 型の変数に代入できますShape。[ 77 ] : 263–268形式言語では、Go のインターフェースシステムは名目型ではなく構造型を提供します。インターフェースは他のインターフェースを埋め込むことができ、その結果、埋め込まれたインターフェースを実装する型と、新しく定義されたインターフェースが追加するメソッドによって満たされる結合インターフェースが作成されます。[ 77 ] : 270
ReaderGo標準ライブラリは、インターフェースを使用して、いくつかの箇所で汎用性を提供しています。これには、との概念に基づいた入出力システムも含まれますWriter。[ 77 ] : 282–283
Go言語では、インターフェースを介してメソッドを呼び出すだけでなく、実行時の型チェックによってインターフェースの値を他の型に変換することもできます。これを行うための言語構造は、単一の潜在的な型に対してチェックを行う型アサーション[ 82 ]です。
var shp Shape = Square { 5 } square , ok := shp .( Square ) // shp が Square 型であることを確認します。 ok が正しければ動作するはずです。 if ok { fmt . Printf ( "%#v\n" , square ) } else { fmt . Println ( "形状を Square として印刷できません" ) }そして、複数の型をチェックする型スイッチ[ 83 ] :
func ( sq Square ) Diagonal ( ) float64 { return sq.side * math.Sqrt2 } func ( c Circle ) Diameter ( ) float64 { return 2 * c.radius }func LongestContainedLine ( shp Shape ) float64 { switch v := shp .( type ) { case Square : return v . Diagonal () // または、型アサーションを使用する場合は、shp.(Square).Diagonal() case Circle : return v . Diameter () // または、型アサーションを使用する場合は、shp.(Circle).Diameter() default : return 0 // 実際には、これはエラーで処理されるべきです} }空のインターフェース は、任意の具体的な型の項目を参照できるため、重要な基本ケースです。これは、 JavaやC#のクラス、CやC ++およびRustのクラスに似ており、組み込み型などを含む任意の型で満たされます。[ 77 ] : 284空のインターフェースを使用するコードは、参照先のオブジェクトのメソッド (または組み込み演算子) を単純に呼び出すことはできませんが、値を格納したり、型アサーションや型スイッチを使用してより有用な型に変換しようとしたり、Go のパッケージを使用して検査したりすることはできます。[ 84 ]は任意の値を参照できるため、C のように静的型付けの制限を回避する限定的な方法ですが、実行時の型チェックが追加されています。interface{}Objectvoid*Anyintinterface{}reflectinterface{}void*
この型は、 JSONやYAMLデータなど、Go言語で任意のスキーマの構造化データをモデル化するために使用できます。これは、文字列から空のインターフェースへのマップとして表現されます。これにより、文字列キーと任意の型の値を持つ辞書の形式でデータが再帰的に記述されます。[ 85 ]interface{}map[string]interface{}
インターフェース値は、データへのポインタと実行時型情報への別のポインタを使用して実装されます。[ 86 ] Go でポインタを使用して実装される他のいくつかの型と同様に、インターフェース値はnil初期化されていない場合は です。[ 87 ]
Goはバージョン1.18以降、パラメータ化された型を使用したジェネリックコードをサポートしています。[ 88 ]
関数と型は、型パラメータを使用してジェネリックにできるようになりました。これらの型パラメータは、関数名または型名の直後に角括弧で囲んで指定します。[ 89 ]コンパイラは、ユーザーが明示的に指定した型パラメータ、またはコンパイラによる型推論によって提供された型引数を置き換えることで、ジェネリック関数または型を非ジェネリックに変換します。[ 90 ]この変換プロセスは、型インスタンス化と呼ばれます。[ 91 ]
インターフェースは、(Union) 演算子を使用して型セット (型セットとして知られています)|とメソッドセットを定義できるようになりました。これらの変更は、ジェネリクス コードで型制約をサポートするために行われました。ジェネリック関数または型の場合、制約は型引数の型、つまりメタ型と考えることができます。この新しい構文は、Go でトークンとして~T初めて使用されます。は、基底型がであるすべての型のセットを意味します。[ 92 ]~~TT
型Numberインターフェース{ ~ int | ~ float64 | ~ float32 | ~ int32 | ~ int64 }func Add [ T Number ]( nums ... T ) T { var sum T for _ , v := range nums { sum += v } return sum }func main () { add := Add [ int ] // 型のインスタンス化println ( add ( 1 , 2 , 3 , 4 , 5 )) // 15res := Add ( 1.1 , 2.2 , 3.3 , 4.4 , 5.5 ) // 型推論println ( res ) // +1.650000e+001 }Go はiota識別子を使用して列挙定数を作成します。[ 93 ] [ 94 ]
型ByteSize intconst ( _ = iota // 最初の値を空の識別子に代入して無視します。0 KB ByteSize = 1 << ( 10 * iota ) // 1 << (10 * 1) == 1 << 10 == 1024; バイナリでは 10000000000 MB // 1 << (10 * 2) == 1048576; バイナリでは 100000000000000000000 GB // 1 << (10 * 3) == 1073741824; バイナリでは 1000000000000000000000000000000 )Go のパッケージ システムでは、各パッケージにはパス (例:"compress/bzip2"または"golang.org/x/net/html") と名前 (例:bzip2またはhtml) があります。デフォルトでは、他のパッケージの定義には常に他のパッケージ名をプレフィックスとして付ける必要があります。ただし、使用する名前はパッケージ名から変更でき、 としてインポートする場合は_パッケージ プレフィックスは不要です。他のパッケージから大文字のio.Reader名前のみがアクセス可能です。は公開されていますが、bzip2.readerは公開されていません。[ 95 ]コマンドgo getはリモート リポジトリに保存されているパッケージを取得できます[ 96 ]。開発者は、標準ライブラリや他の外部ライブラリへの将来の追加との名前の衝突の可能性を減らすために、ソース リポジトリに対応するベース パス (例: example.com/user_name/package_name) 内にパッケージを開発することが推奨されています。[ 97 ]
Go言語には、並行プログラムを作成するための組み込み機能とライブラリサポートがあります。ランタイムは非同期です。たとえば、ネットワーク読み取りを実行するプログラムの実行は、処理可能なデータが利用可能になるまで中断され、プログラムの他の部分が他の作業を実行できるようになります。これはランタイムに組み込まれており、プログラムコードの変更は必要ありません。Goランタイムはまた、複数のCPU間で並行操作(ゴルーチン)を自動的にスケジュールします。これにより、適切に記述されたプログラムで並列処理を実現できます。[ 98 ]
主要な並行処理構成要素は、グリーンスレッドの一種であるゴルーチンです。[ 99 ] : 280–281キーワードで始まる関数呼び出しは、新しいゴルーチンで関数を開始します。言語仕様ではゴルーチンの実装方法は規定されていませんが、現在の実装では、ErlangやHaskellのGlasgow Haskell Compiler (GHC)ランタイム実装で行われるスケジューリングと同様に、 Goプロセスのゴルーチンをより少ない数のオペレーティングシステムスレッドに多重化しています。[ 100 ] : 10go
古典的な並行制御構造(ミューテックスロックなど)のほとんどを備えた標準ライブラリパッケージが利用可能である一方、 [ 100 ] : 151-152慣用的な並行プログラムは、ゴルーチン間でメッセージを送信するチャネルを好みます。[ 101 ]オプションのバッファはメッセージをFIFO順に格納し[ 102 ] : 43送信ゴルーチンがメッセージを受信する前に処理を続行できるようにします。[ 99 ] : 233
チャネルには型があり、型のチャネルはchan T型のメッセージの転送にのみ使用できますT。チャネルを操作するには特別な構文を使用します。<-chは、チャネル経由で値が受信されるまで実行中のゴルーチンをブロックする式でありch、はch <- x値を送信しますx(別のゴルーチンが値を受信するまでブロックする可能性があります)。組み込みののswitchようなselectステートメントを使用して、複数のチャネルで非ブロッキング通信を実装できます。例については以下を参照してください。Goには、ゴルーチンがチャネルやその他の操作を使用してデータを安全に共有する方法を記述したメモリ モデルがあります。[ 103 ]
チャネルの存在自体は、メッセージがアクター(ゴルーチンに対応)に直接送信されるErlangのようなアクターモデル型の並行言語とGoを区別するものではありません。アクターモデルでは、チャネル自体がアクターであるため、チャネルにアドレスを指定することは、アクターにアドレスを指定することを意味します。アクター型は、ゴルーチンとチャネルを1対1で対応させることでGoでシミュレートできますが、Goでは複数のゴルーチンがチャネルを共有したり、1つのゴルーチンが複数のチャネルで送受信したりすることも可能です。[ 100 ] : 147
これらのツールから、ワーカー プール、パイプライン (たとえば、ファイルがダウンロードされる際に解凍および解析される)、タイムアウト付きバックグラウンド呼び出し、一連のサービスへの「ファンアウト」並列呼び出しなど、並行構造を構築できます。 [ 104 ]また、チャネルは、通常のプロセス間通信の概念からさらに離れた用途も見つけており、リサイクル バッファの並行安全なリストとして機能したり、[ 105 ]コルーチンを実装したり(これがgoroutineという名前のインスピレーションになりました)、[ 106 ]イテレータを実装したりしています。[ 107 ]
Go の並行処理に関連する構造的慣習 (チャネルと代替チャネル入力) は、Tony Hoare の通信シーケンシャル プロセス モデルから派生しています。OccamやLimbo (Go の共同設計者である Rob Pike が携わった言語) などの以前の並行プログラミング言語とは異なり、[ 108 ] Goは安全または検証可能な並行処理の概念を組み込みで提供していません。[ 109 ]通信プロセス モデルは Go で好まれていますが、唯一のモデルではありません。プログラム内のすべてのゴルーチンは単一のアドレス空間を共有します。これは、可変オブジェクトとポインタがゴルーチン間で共有される可能性があることを意味します。§ データ競合の安全性の欠如を参照してください。
Go の並行処理機能は主に並列処理を目的としているわけではないが、[ 98 ]共有メモリのマルチプロセッサマシンをプログラミングするために使用できる。このアプローチの有効性についてはさまざまな研究が行われている。[ 110 ]これらの研究の 1 つは、言語に精通していない熟練プログラマが書いたプログラムと、それらのプログラムに対する Go のエキスパート (Google の開発チーム) による修正のサイズ (コード行数) と速度を比較し、 Chapel、Cilk、およびIntel TBBについても同様の調査を行った。この研究では、エキスパートでないプログラマは再帰ごとに 1 つのステートメントを持つ分割統治アルゴリズムを書く傾向があるgoのに対し、エキスパートはプロセッサ コアごとに 1 つのゴルーチンを使用して分散作業同期プログラムを書く傾向があることがわかった。エキスパートのプログラムは通常高速であったが、長かった。[ 111 ]
Go の並行処理へのアプローチは、「メモリを共有して通信するのではなく、通信してメモリを共有する」と要約できます。[ 112 ]ゴルーチンが共有データにアクセスする方法に制限がないため、データ競合が発生する可能性があります。具体的には、プログラムがチャネルまたはその他の手段で明示的に同期しない限り、あるゴルーチンからの書き込みは、別のゴルーチンから部分的に、完全に、またはまったく見えない可能性があり、多くの場合、書き込みの順序に関する保証はありません。[ 109 ]さらに、インターフェース値、スライス ヘッダー、ハッシュ テーブル、文字列ヘッダーなどの Go の内部データ構造はデータ競合の影響を受けないため、同期せずにこれらの型の共有インスタンスを変更するマルチスレッド プログラムでは、型とメモリの安全性が侵害される可能性があります。[ 113 ] [ 114 ]したがって、安全な並行プログラミングは、言語サポートではなく、規約に依存します。例えば、Chisnall は「aliases xor mutable」という慣用表現を推奨しています。これは、可変値 (またはポインタ) をチャネル経由で渡すと、その値の所有権が受信者に移転されることを意味します。[ 100 ] : 155 gc ツールチェーンには、バージョン 1.1 以降、実行時に共有メモリへの非同期アクセスをチェックできるオプションのデータ競合検出器があります。[ 115 ]さらに、gc ランタイムのバージョン 1.6 以降では、データ型へのアクセスに対してベストエフォート型の競合検出器もデフォルトで含まれていますmap。[ 116 ]
gcツールチェーンのリンカーはデフォルトで静的にリンクされたバイナリを作成するため、すべてのGoバイナリにはGoランタイムが含まれます。[ 117 ] [ 118 ]
Go は、他の言語で一般的な特定の機能、例えば(実装) 継承、アサーション、[ f ]ポインタ演算、[ e ]暗黙的な型変換、タグなし共用体、[ g ]およびタグ付き共用体[ h ]などを意図的に省略しています。設計者は、3 名全員が同意した機能のみを追加しました。[ 121 ]
省略された言語機能のうち、設計者はアサーションとポインタ演算に明確に反対し、型継承を省略した選択はより有用な言語をもたらすとして擁護し、代わりに動的ディスパッチ[ i ]とコードの再利用のためのコンポジションの使用を推奨している。コンポジションと委譲は実際には埋め込みによって大部分が自動化されている。研究者の Schmagerらによると、この機能は「継承の多くの欠点がある。オブジェクトのパブリックインターフェイスに影響を与え、きめ細かくなく(つまり、埋め込みに対するメソッドレベルの制御がなく)、埋め込まれたオブジェクトのメソッドを隠すことができず、静的である」ため、プログラマが他の言語のプログラマが継承を過剰に使用すると言われているほど過剰に使用するかどうかは「明らかではない」。[ 76 ]struct
Go では、当初は「複雑さに見合った価値を提供する設計」がなかったため、例外処理は省略されていました。 [ 122 ]通常の制御構造を回避する例外のようなpanicメカニズムが提案され[ 123 ]、2010 年 3 月 30 日のスナップショットでリリースされました。[ 124 ] Go の開発者は、プログラム全体やサーバー要求を停止させるような回復不能なエラー、またはパッケージ内でスタックを上方向にエラーを伝播させるショートカットとして使用することを推奨しています。[ 125 ] [ 126 ]パッケージの境界を越えて、Go には標準的なエラー型が含まれており、この型を使用した複数値の戻り値が標準的な慣用表現となっています。[ 4 ]recovertry-catch
Go言語の開発者たちは、Goプログラムのスタイルに影響を与えるために多大な努力を払った。
gofmtツールによって自動的に標準化されます。インデントにはタブ、整列には空白を使用します。整列は、エディタが固定幅フォントを使用していることを前提としています。[ 127 ]golintは追加のスタイルチェックを自動的に行いますが、Goメンテナーによって非推奨となりアーカイブされています。[ 128 ]godocGo に付属するツールやライブラリは、API ドキュメント ( )、[ 129 ]テスト ( go test)、ビルド ( go build)、パッケージ管理 ( )などに対する標準的なアプローチを提案していますgo get。maptryfinallyGoのメインディストリビューションには、コードの構築、テスト、分析を行うためのツールが含まれています。
go buildソースファイル自体に含まれる情報のみを使用してGoバイナリをビルドし、別途メイクファイルは使用しません。go testユニットテストやマイクロベンチマーク、ファジングにも使用できます。go fmtコードの書式設定についてgo installリモートパッケージの取得とインストールgo vet静的解析ツールは、コード内の潜在的なエラーを探します。go runコードの構築と実行のためのショートカットgo docドキュメントを表示するためgo generateコードジェネレータを呼び出す標準的な方法go mod新しいモジュールの作成、依存関係の追加、依存関係のアップグレードなどを行うために使用します。go tool開発者ツールを呼び出すためのもの(Goバージョン1.24で追加)また、プロファイリングとデバッグのサポート、バグを検出するためのファジング機能、ランタイム計測(例えば、ガベージコレクションの一時停止を追跡するため)、およびデータ競合検出器も含まれています。
Go チームによってメンテナンスされているが Go ディストリビューションには含まれていない別のツールは、言語サーバープロトコル互換のエディタにインテリジェントなコード補完などのIDEgopls機能を提供する言語サーバーです。 [ 135 ]
サードパーティ製のツール群が標準ディストリビューションに追加されており、例えばgocode、多くのテキストエディタでコードの自動補完を可能にするものgoimports、必要に応じてパッケージのインポートを自動的に追加/削除するもの、errcheck意図せずエラーを無視してしまう可能性のあるコードを検出するものなどがあります。
パッケージメインimport "fmt"func main () { fmt.Println ( " hello world " ) }ここで「fmt」は、C言語の<stdio.h>やC++の<print>に似た、フォーマット付き入出力のためのパッケージです。[ 136 ]
以下の簡単なプログラムは、Goの並行処理機能を用いて非同期プログラムを実装する方法を示しています。このプログラムは2つの軽量スレッド(「ゴルーチン」)を起動します。1つはユーザーがテキストを入力するのを待ち、もう1つはタイムアウト処理を実行します。select文は、これらのゴルーチンのいずれかがメインルーチンにメッセージを送信するのを待ち、最初に到着したメッセージに基づいて処理を実行します(この例はDavid Chisnallの著書から引用)。[ 100 ] : 152
パッケージメインimport ( "fmt" "time" )func readword ( ch chan string ) { fmt.Println ( "単語を入力してEnterキーを押してください。" ) var word string fmt.Scanf ( " % s " , & word ) ch <- word }func timeout ( t chan bool ) { time.Sleep ( 5 * time.Second ) t < - false }func main () { t := make ( chan bool ) go timeout ( t )ch := make ( chan string ) go readword ( ch )select { case word := <- ch : fmt . Println ( "Received" , word ) case <- t : fmt . Println ( "Timeout." ) } }テストパッケージは、Goパッケージの自動テストをサポートします。[ 137 ]ターゲット関数の例:
func ExtractUsername ( email string ) string { at := strings.Index ( email , " @" ) return email [ : at ] }テストコード( Go言語にはassertキーワードがないことに注意してください。テストは同じパッケージ内の<filename>_test.goにあります):
import ( "testing" )func TestExtractUsername ( t * testing . T ) { t . Run ( "withoutDot " , func ( t * testing . T ) { username := ExtractUsername ( "r@google.com" ) if username != "r" { t . Fatalf ( "Got: %v\n" , username ) } })t.Run ( " withDot " , func ( t * testing.T ) { username := ExtractUsername ( "jonh.smith@example.com" ) if username != "jonh.smith" { t.Fatalf ( " Got : %v\n " , username ) } } ) }テストを並列実行することが可能です。
net /http [ 138 ]パッケージは、Web アプリケーションの作成をサポートします。
この例では、localhost:8080 にアクセスすると「Hello world!」と表示されます。
パッケージメインimport ( "fmt" "log" "net/http" )func helloFunc ( w http.ResponseWriter , r * http.Request ) { fmt.Fprintf ( w , " Hello world ! " ) }func main () { http.HandleFunc ( " / " , helloFunc ) log.Fatal ( http.ListenAndServe ( " : 8080 " , nil ) ) }Go言語は、その堅牢な標準ライブラリと使いやすさから、さまざまな分野で広く採用されている。[ 139 ]
人気のあるアプリケーションには以下が含まれます。
インターフェースシステムと、継承を意図的に省略した点は、ミケーレ・シミオナートによって称賛され、彼はこれらの特徴をStandard MLの特徴になぞらえ、「人気のある言語が[この]特定の道を辿っていないのは残念だ」と述べた。[ 145 ]
Engine YardのDave Astelsは2009年に次のように書いています。[ 146 ]
Go言語は非常に習得しやすい言語です。基本的な言語概念は最小限に抑えられており、構文は簡潔で、明確かつ曖昧さのないように設計されています。ただし、Go言語はまだ実験段階であり、多少粗削りな部分もあります。
Go は、2009 年の初年度にTIOBE プログラミング コミュニティ インデックスで年間最優秀プログラミング言語に選ばれました。これは、12 か月間の人気上昇率がその年のどの言語よりも大きかったためです (11 月に導入されてからわずか 2 か月で)。2010 年 1 月までに 13 位に達し、 Pascalなどの確立された言語を上回りました。 [ 147 ] 2015 年 6 月までに、インデックスでの順位は 50 位以下に下がり、COBOLやFortranよりも低い順位になりました。[ 148 ]しかし、2017 年 1 月時点では、順位は 13 位に急上昇し、人気と採用が大幅に増加したことが示されました。Go は 2016 年にも再び TIOBE 年間最優秀プログラミング言語に選ばれました。[ 149 ]
ブルース・エッケルは次のように述べている。[ 150 ]
C++の複雑さ(新しいC++ではさらに複雑化している)と、それに伴う生産性への影響は、もはや正当化できない。C++プログラマーがC互換言語を使うために乗り越えなければならなかった数々の困難は、もはや意味をなさない。それは時間と労力の無駄遣いに過ぎない。C++が本来解決しようとしていた種類の問題には、Goの方がはるかに適している。
2011年にGoogleのエンジニアが行った、 C++( GCC)、Java、Scalaと比較した言語とそのガベージコレクション実装の評価では、以下のことが判明した。
Go言語は、簡潔で標準化された表記を可能にする興味深い言語機能を備えています。しかし、この言語のコンパイラはまだ未成熟であり、それはパフォーマンスとバイナリサイズの両方に反映されています。
— R. フント[ 151 ]
この評価に対し、Go開発チームから反論があった。ハントの論文のためにGoコードを改良したイアン・ランス・テイラーは、自分のコードを公開する意図を知らなかったと述べ、自分のバージョンは「慣用的または効率的なGoの例として意図されたものではなかった」と述べている。その後、ラス・コックスがGoコードとC++コードを最適化し、GoコードをC++バージョンとほぼ同じ速度で実行させ、論文のコードよりも1桁以上高速にした。[ 152 ]
2009年11月10日、言語の一般公開の日に、Go!プログラミング言語の開発者であるフランシス・マッケイブ(感嘆符に注意)は、10年かけて開発した自身の言語との混同を避けるため、Googleの言語の名前を変更するよう要求した。[ 158 ]マッケイブは、「大企業が最終的に自分を圧倒してしまう」という懸念を表明し、この懸念は、Googleの公式問題スレッドに名前を変更すべきだとコメントした120人以上の開発者の共感を呼び、中には[ 159 ]この問題はGoogleのモットーである「悪事を働くな」に反すると述べる者もいた。[ 160 ]
2010年10月12日、Google開発者のRuss Cox氏(@rsc)により、提出された公開問題チケットが「残念」というカスタムラベルとともに以下のコメントとともにクローズされました。
「Goという名前のコンピューティング製品やサービスは数多く存在します。リリースから11ヶ月が経過しましたが、2つの言語の混同はほとんどありませんでした。」[ 160 ]
言語は、第一級関数、高階関数、ユーザー定義関数型、関数リテラル、クロージャ、および複数の戻り値をサポートしています。この豊富な機能セットにより、厳密な型付け言語で関数型プログラミングスタイルを実現できます。
には型とメソッドがあり、オブジェクト指向スタイルのプログラミングが可能ですが、型階層はありません。
はオブジェクト指向だが、一般的な方法とは異なる。
この言語はGoと呼ばれています。
コンパイラとランタイムは、C 言語を使用せずに Go 言語とアセンブラで実装されるようになりました。
は、Goプログラミング言語用のGNUコンパイラです。
はLLVMベースのGoコンパイラです。
は、CやC++などの低レベルプログラミングの世界の巨人を改良するという野心的な試みである、Goプログラミング言語のバージョン1をリリースしました。
の iota 識別子は、定数宣言で使用され、インクリメントされる数値の定義を簡素化します。式で使用できるため、単純な列挙よりも汎用性があります。
では、情報の可視性に関するルールは単純です。名前(トップレベルの型、関数、メソッド、定数または変数、あるいは構造体のフィールドまたはメソッド)が大文字で始まる場合、パッケージのユーザーはそれを見ることができます。そうでない場合、名前、したがって名前が付けられているものは、それが宣言されているパッケージ内でのみ可視です。
標準ライブラリのパッケージには、「fmt」や「net/http」のような短いインポートパスが割り当てられています。独自のパッケージの場合は、標準ライブラリや他の外部ライブラリへの将来の追加と競合する可能性の低いベースパスを選択する必要があります。コードをソースリポジトリに保存している場合は、そのソースリポジトリのルートをベースパスとして使用する必要があります。たとえば、example.com/userにExampleアカウントを持っている場合は、それがベースパスになります。
例えば、ブロッキングバグの約58%はメッセージパッシングが原因です。Goのチャネル使用規則違反(例えば、誰もデータを送信していない、または閉じていないチャネルで待機するなど)に加えて、多くの並行性バグは、メッセージパッシングとGoの他の新しいセマンティクスや新しいライブラリの混在した使用によって引き起こされます。これらは見落とされやすいものの、検出は困難です。