Pregunta ¿Cómo definir un tipo de función que acepte cualquier número de argumentos en Go?


Intento escribir una función que toma cualquier otra función y envuelve una nueva función a su alrededor. Esto es lo que he intentado hasta ahora:

paquete principal

importar
    "fmt"
)

func protect (función desprotegida (... interfaz {})) (func (... interfaz {})) {
    return func (args ... interface {}) {
        fmt.Println ("protegido");
        desprotegido (args ...);
    };
}

func main () {
    a: = func () {
        fmt.Println ("desprotegido");
    };
    b: = proteger (a);
    b ();
}

Cuando compilo esto me sale el error:

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

¿Por qué una función sin argumentos no es compatible con una función con un número variable de argumentos? ¿Qué puedo hacer para que sean compatibles?

Actualizar: La función protegida debe ser compatible con el original:

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

func main () {

    a: = func (x int) (y int) {
        devuelve 2 * x
    }
    b: = proteger (a)

    take_func_int_int (a)
    take_func_int_int (b)
}

5
2018-05-18 15:48


origen


Respuestas:


Los tipos son bastante concretos en Go. Tu podrías intentar

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

func (...interface{}) no significa "cualquier función que tome cualquier número de cualquier tipo de argumentos", significa "solo una función que toma un número variable de argumentos de interfaz {}"

Alternativamente en lugar de func(...interface{}) solo puedes usar interface{} y el reflect paquete. Ver http://github.com/hoisie/web.go para un ejemplo.

EDITAR: Específicamente, esto:

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 es

Protected
unprotected
Protected
hello

EDITAR: Para responder a la actualización.

Como dije antes, los tipos son bastante concretos en Go. La función de protección devuelve un tipo func(...interface{}) que lo hará Nunca ser asignable a func(int)int. Creo que es probable que estés superando la ingeniería de tu problema o entendiéndolo mal. Sin embargo, aquí hay una muy desalentado código que lo haría funcionar.

Primer cambio de protección para devolver también los valores:

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
    }
}

A continuación, realice una función de conversión:

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

Entonces tu llamada se vería como

take_func_int_int(convert(b))

Pero prometo que esto no es lo que realmente quieres hacer.

Retrocede y trata de volver a trabajar el problema. He matado por completo la seguridad de tipo en estos ejemplos. ¿Qué está tratando de lograr?


11
2018-05-18 16:35