6

私はタイプセーフに慣れていないので、次のことを行う方法がわかりません

package main

func test(){
    print("In Test")
}

func main(){
    a := "test"
    a()
}
4

3 に答える 3

14

通常、熟考は最善の方法ではないため、達成しようとしていることを述べると、より良い答えが得られる可能性があります。ただし、関数が型のメソッドである場合は、リフレクトが役立ちます ( net/rpcこの例です)。

package main

import (
    "fmt"
    "reflect"
)

type T struct {}

func (T) Add(x, y int) int {
    return x + y
}

func main() {
    t := reflect.ValueOf(T{})
    m := t.MethodByName("Add")
    args := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
    fmt.Println(m.Call(args)[0].Int())
}

godocのようなツールがどのように機能するのか疑問に思っているなら、それらはリフレクションを使用するのではなく、ソースを解析します。

編集:遊び場バージョン

于 2012-08-26T10:42:08.053 に答える
8

関数を名前で動的に検索する方法はありませんが、その理由について言及する価値はあると思います。基本的には、コンパイラやリンカが未使用の関数を削除できるようにするためです。

名前で関数を取得できた場合、インポートされたすべてのパッケージのすべての関数を (再帰的に) 最終的な実行可能ファイルにリンクする必要があることを考慮してください。名前。人々はすでに Go バイナリのサイズが大きいことに不満を持っていますが、これによりさらにサイズが大きくなるでしょう。

于 2012-08-26T07:30:58.040 に答える
8

関数は文字列から解決できません。ただし、関数を変数に割り当てることはできます。

a := test
a()

関数をマップに入れることもできます (それらはすべて同じシグネチャを持っていると仮定します):

var func_map :=  map[string]func() {
    "test": test,
}
a := func_map["test"]
a()


OP による最初のコメントへの応答 (別のコメントを作成するには長すぎます):

  1. 関数は「リテラル」ではありません。「リテラル」には別の意味があります。
  2. 次に、Go のランタイム リフレクションには、文字列を関数にマッピングするルックアップ テーブルがありません。たとえそうであったとしても、他のコードによってリンクされない限り、関数はバイナリにリンクされません。このメソッドでのみ呼び出されるコードは、バイナリには含まれません。
  3. 第 3 に、手動でマッピングを作成することはそれほど難しくありません。コンパイル時の型の安全性チェックとセキュリティを提供します。
  4. これは、どの言語でも行うべきことではありません。これは eval() のようなものですが、信じられないほど危険であり、予測できないことが起こる可能性があるため、実際には使用しないでください。

それらはすべて同じ署名を持っているわけではありません

それらがすべて同じ署名を持っていない場合、どのようにそれらを呼び出す予定ですか? パッケージを使用することもできますreflectが、それは通常、何か間違ったことをしていることを示しています。

これは動的言語ではなく、Go で実行できないこともあります。ただし、これらはほとんどの言語で行うべきではないことがほとんどです。

于 2012-08-26T04:25:49.080 に答える