Как определить тип функции, который принимает любое количество аргументов в Go? - PullRequest
7 голосов
/ 18 мая 2011

Я пытаюсь написать функцию, которая принимает любую другую функцию и оборачивает вокруг нее новую функцию.Это то, что я пробовал до сих пор:

package main

import (
    "fmt"
)

func protect (unprotected func (...interface{})) (func (...interface{})) {
    return func (args ...interface{}) {
        fmt.Println ("protected");
        unprotected (args...);
    };
}

func main () {
    a := func () {
        fmt.Println ("unprotected");
    };
    b := protect (a);
    b ();
}

Когда я компилирую это, я получаю ошибку:

cannot use a (type func()) as type func(...interface { }) in function argument

Почему функция без аргументов не совместима с функцией с переменнойколичество аргументов?Что я могу сделать, чтобы сделать их совместимыми?

Обновление: Защищенная функция должна быть совместима с оригиналом:

func take_func_int_int (f func (x int) (y int)) (int) {
    return f (1)
}

func main () {

    a := func (x int) (y int) {
        return 2 * x
    }
    b := protect (a)

    take_func_int_int (a)
    take_func_int_int (b)
}

Ответы [ 2 ]

12 голосов
/ 18 мая 2011

Типы довольно конкретные в Go.Вы можете попробовать

a := func(_ ...interface{}) {
    fmt.Println("unprotected")
}

func (...interface{}) не означает «любая функция, которая принимает любое количество аргументов любого типа», это означает «только функцию, которая принимает переменное число аргументов интерфейса {}»

В качестве альтернативы вместо func(...interface{}) вы можете просто использовать interface{} и пакет reflect.См. http://github.com/hoisie/web.go для примера.

РЕДАКТИРОВАТЬ: В частности, это:

package main

import (
    "fmt"
    "reflect"
)

func protect(oldfunc interface{}) (func (...interface{})) {
    if reflect.TypeOf(oldfunc).Kind() != reflect.Func {
        panic("protected item is not a function")
    }
    return func (args ...interface{}) {
        fmt.Println("Protected")
        vargs := make([]reflect.Value, len(args))
        for n, v := range args {
            vargs[n] = reflect.ValueOf(v)
        }
        reflect.ValueOf(oldfunc).Call(vargs)
    }
}

func main() {
    a := func() {
        fmt.Println("unprotected")
    }
    b := func(s string) {
        fmt.Println(s)
    }
    c := protect(a)
    d := protect(b)
    c()
    d("hello")
}

Ouput is

Protected
unprotected
Protected
hello

РЕДАКТИРОВАТЬ: ответить на обновление

Как я уже говорил выше, типы в Go довольно конкретны.Функция защиты возвращает тип func(...interface{}), который никогда не будет назначаться на func(int)int.Я думаю, что вы, вероятно, либо чрезмерно продумали свою проблему, либо неправильно ее поняли.Тем не менее, вот код крайне обескураженный кода, который заставил бы его работать.

Сначала измените защиту и верните значения:

func protect(oldfunc interface{}) (func (...interface{}) []interface{}) {
    if reflect.TypeOf(oldfunc).Kind() != reflect.Func {
        panic("protected item is not a function")
    }
    return func (args ...interface{}) []interface{} {
        fmt.Println("Protected")
        vargs := make([]reflect.Value, len(args))
        for n, v := range args {
            vargs[n] = reflect.ValueOf(v)
        }
        ret_vals := reflect.ValueOf(oldfunc).Call(vargs)
        to_return := make([]interface{}, len(ret_vals))
        for n, v := range ret_vals {
                to_return[n] = v.Interface()
        }
        return to_return
    }
}

Затем сделайте функцию преобразования:

func convert(f func(...interface{}) (func(int) int) {
    return func(x int) int {
        r := f(x)
        return r[0].(int)
    }
}

Тогда ваш звонок будет выглядеть так:

take_func_int_int(convert(b))

Но я обещаю, что это не то, что вы на самом деле хотите сделать.

Отойдите назад и попытайтесь переделатьпроблема.Я полностью убил безопасность типов в этих примерах.Что вы пытаетесь достичь?

0 голосов
/ 17 ноября 2018
package main

import "fmt"

// Here's a function that will take an arbitrary number
// of `int`s as arguments.
func sum(nums ...int) {
    fmt.Print(nums, " ")
    total := 0
    for _, num := range nums {
        total += num
    }
    fmt.Println(total)
}

func main() {

    // Variadic functions can be called in the usual way
    // with individual arguments.
    sum(1, 2)
    sum(1, 2, 3)

    // If you already have multiple args in a slice,
    // apply them to a variadic function using
    // `func(slice...)` like this.
    nums := []int{1, 2, 3, 4}
    sum(nums...)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...