C/C++(およびそのファミリーの多くの言語)では、条件に応じて変数を宣言および初期化するための一般的な慣用句では、3項条件演算子を使用します。
int index = val > 0 ? val : -val
Goには条件演算子がありません。上記と同じコードを実装するための最も慣用的な方法は何ですか?私は次の解決策を見つけました、しかしそれはかなり冗長に思えます
var index int
if val > 0 {
index = val
} else {
index = -val
}
もっと良いものはありますか?
指摘されたように(そしてうまくいけば驚くことではないが)、if+else
を使うことはGoで条件付きをするための 慣用的な方法 です。
本格的なvar+if+else
コードブロックに加えて、このスペルもよく使われます。
index := val
if val <= 0 {
index = -val
}
int value = a <= b ? a : b
と同等の十分に反復的なコードブロックがある場合は、それを保持する関数を作成できます。
func min(a, b int) int {
if a <= b {
return a
}
return b
}
...
value := min(a, b)
コンパイラーはそのような単純な関数をインライン化するので、高速、明瞭、そして短くなります。
No Goは三項演算子を持っていません。if/else構文を使用するのは慣用法です: http://golang.org/doc/faq#Does_Go_have_a_ternary_form
次の三項式があるとします(C言語)。
int a = test ? 1 : 2;
Goでの慣用的なアプローチは、単純にif
ブロックを使うことです。
var a int
if test {
a = 1
} else {
a = 2
}
しかし、それはあなたの要求に合わないかもしれません。私の場合は、コード生成テンプレート用のインライン式が必要でした。
私はすぐに評価された無名関数を使いました:
a := func() int { if test { return 1 } else { return 2 } }()
これにより、両方の分岐が同様に評価されないようになります。
マップの三項は括弧なしで読みやすいです。
c := map[bool]int{true: 1, false: 0} [5 > 4]
func Ternary(statement bool, a, b interface{}) interface{} {
if statement {
return a
}
return b
}
func Abs(n int) int {
return Ternary(n >= 0, n, -n).(int)
}
これはif/elseよりも性能が上がらず、キャストが必要ですが機能します。参考:
ベンチマークAbbsTernary-8 100000000 18.8 ns/op
BenchmarkAbsIfElse-8 2000000000 0.27 ns/op
すべてあなたの枝が副作用をするか、または計算上高価である場合、 意味的に保存されたリファクタリング
index := func() int {
if val > 0 {
return printPositiveAndReturn(val)
} else {
return slowlyReturn(-val) // or slowlyNegate(val)
}
}(); # exactly one branch will be evaluated
通常はオーバーヘッドはありません(インライン)、そして最も重要なことに、一度だけ使用されるヘルパー関数で名前空間を乱雑にすることなく(読みやすさと保守を妨げる) 実例
単純に Gustavoのアプローチ を単純に適用したのであれば注意してください。
index := printPositiveAndReturn(val);
if val <= 0 {
index = slowlyReturn(-val); // or slowlyNegate(val)
}
あなたは異なる振る舞いを持つプログラムを手に入れるでしょう。 val <= 0
プログラムが正ではない値を表示しますが、そうではありません! (同様に、分岐を逆にした場合、不必要に遅い関数を呼び出すことでオーバーヘッドが発生します。)
eoldの答えは面白くて創造的で、おそらくさらに賢いかもしれません。
ただし、代わりに次のようにすることをお勧めします。
var index int
if val > 0 {
index = printPositiveAndReturn(val)
} else {
index = slowlyReturn(-val) // or slowlyNegate(val)
}
はい、どちらも基本的に同じアセンブリにコンパイルされますが、このコードは、最初に変数に書き込まれた可能性のある値を返すためだけに無名関数を呼び出すよりもはるかに読みやすくなります。
基本的に、シンプルで明確なコードはクリエイティブなコードより優れています。
また、Goはマップがまったく軽量ではないため、マップリテラルを使用するコードは推奨されません。 Go 1.3以降、小さなマップに対するランダムな反復順序は保証されており、これを強制するために、小さなマップに対してはメモリ効率がかなり低くなっています。
その結果、多数の小さなマップを作成および削除することは、スペースと時間がかかります。私は小さな地図を使ったコードをいくつか持っていました(2つか3つのキーがありますが、一般的な使用例は1つのエントリだけでした)。同じコードをデュアルスライスキー[index] => data [index] mapを使って書き直すよりも少なくとも3桁遅くなります。そしてもっとありそうです。以前は実行に数分かかっていた操作の一部として、ミリ秒で完了し始めました。