web-dev-qa-db-ja.com

golangで複数のリターンを解析する方法

2つの整数値を返すGo関数があります。以下は機能です

func temp() (int, int){
 return 1,1
}

temp関数を直接Printlnに入れて、以下のように文字列フォーマットを使用して両方の出力を出力することは可能ですか?

fmt.Println("first= %d and second = %d", temp() ) // This doesn't work

Pythonでは、次のことができます。

def func():
    return 1,1
print("{0}={1}".format(*func())
>> '1=2'

Goでも同様のことができますか?

5
InAFlash

まず、前者だけがフォーマット文字列を期待して使用するため、 fmt.Printf() の代わりに fmt.Println() を使用する必要があります。

今後、 Spec:Calls: から引用するため、これはデフォルトではサポートされません。

特別な場合として、関数またはメソッドgの戻り値の数が等しく、別の関数またはメソッドfのパラメーターに個別に割り当てることができる場合は、f(g(parameters_of_g))を呼び出します。 fの戻り値をgのパラメーターに順番にバインドした後、fを呼び出します。 fの呼び出しには、gの呼び出し以外のパラメーターを含めることはできず、gには少なくとも1つの戻り値が必要です。fに最後の...パラメータがある場合、通常のパラメータの割り当て後に残るgの戻り値が割り当てられます。

そして、fmt.Printf()には次の署名があります。

func Printf(format string, a ...interface{}) (n int, err error)

関数呼び出し(呼び出しの戻り値)以外のパラメーターをfmt.Printf()に渡すことはできません。

fmt.Println()の署名は次のとおりであることに注意してください。

func Println(a ...interface{}) (n int, err error)

つまり、引用部分の最後の文でこれが許可されているため、fmt.Println(temp())が機能し、少なくとも1つの戻り値を持つ他の関数でも機能します( "If fには最後の...パラメータがあり、通常のパラメータの割り当て後に残るgの戻り値が割り当てられます。 "

しかし、ちょっとしたトリックで、fmt.Printf()でもあなたが望むものを達成することができます。

temp()がタイプ[]interface{}の値を返す場合は、...を使用して可変個引数パラメーターの値として渡すことができることに注意してください。

これが機能することの意味:

func main() {
    fmt.Printf("1: %v, 2: %v\n", temp()...)
}

func temp() []interface{} { return []interface{}{1, 2} }

そしてそれは正しく印刷します( Go Playground で試してください):

1: 1, 2: 2

したがって、関数の戻り値を[]interface{}にラップするユーティリティ関数が必要です。これを使用して、fmt.Printf()に渡すことができます。

そして、それは非常に単純です:

func wrap(vs ...interface{}) []interface{} {
    return vs
}

上で詳述したように(fmt.Println()を使用)、少なくとも1つの戻り値を持つ関数の戻り値を入力パラメーターの値としてwrap()に渡すことができます。

このwrap()関数を使用して、次の例を参照してください。

func main() {
    fmt.Printf("1: %v\n", wrap(oneInt())...)
    fmt.Printf("1: %v, 2: %v\n", wrap(twoInts())...)
    fmt.Printf("1: %v, 2: %v, 3: %v\n", wrap(threeStrings())...)
}

func oneInt() int { return 1 }

func twoInts() (int, int) { return 1, 2 }

func threeStrings() (string, string, string) { return "1", "2", "3" }

これは機能し、出力します( Go Playground で試してください):

1: 1
1: 1, 2: 2
1: 1, 2: 2, 3: 3

このトピックの詳細については、関連する質問を参照してください:

単一値のコンテキストでの複数の値

通常の関数でGolangの「ok」のようなマップを返す

3
icza

いいえ、これは不可能です。それらを使用するには、複数値式のすべての値を個別の変数に割り当てる必要があります。例:

a, b := temp()
fmt.Println("first = %d and second = %d", a, b)
// first = 1 and second = 1

[編集]

興味深いことに、引数の型とアリティが一致する場合、または純粋に可変個引数関数の場合、関数呼び出し引数として複数値式を使用できる場合があるようです( Go Playground ):

func oneTwo() (int, int) {
  return 1, 2
}

func incr2(x, y int) (int, int) {
  return x + 1, y + 1
}

func main() {
  incr2(oneTwo()) // OK: multi-value return and arguments match.

  fmt.Println(oneTwo()) // OK: pure variadic function.

  fmt.Printf("%d %d", oneTwo()) // ERR: mixed formal and variadic args.
}
5
maerics

以下のような文字列フォーマットを使用しなかったときに印刷できました

fmt.Println(temp())

これはPrintlnでのみサポートされていましたが、printfではサポートされていませんでした

0
InAFlash