Пустой интерфейс {} в типе функции

Объект любого типа может быть назначен пустому интерфейсу. Например, у нас есть следующая функция

func Println(i interface{} ) {
  fmt.Println(i)
}

Мы можем позвонить по

Println(3)
Println(1.5)
Println("Hello")

Но я не могу добиться того же самого для типа функции

func Map(fn func( interface{} )) {  
  ......  
}  

Я не могу назвать это с помощью
Map( func( i int) {......} )
потому что тип func(int) отличается от типа func( interface{} ).

Но когда я определяю func( interface{} ), я действительно имею в виду любой тип входных параметров. Как я могу добиться этого в Go?

Ответ 1

Он терпит неудачу, потому что подписи не совпадают.

Когда вы вызываете Println(3), функция не принимает целое число в качестве своего первого аргумента. Скорее целое число упаковывается внутри переменной interface{} (автоматическое преобразование, поскольку целые числа соответствуют интерфейсу), и эта переменная передается функции. Это преобразование происходит на вызывающей стороне, поэтому процесс вызова функции отличается от вызова функции, соответствующей func(i int).

Если вы хотите написать функцию, которая принимает произвольные унарные функции, вам нужно будет объявить ее в качестве аргумента переменной interface{}, а затем проверить значение с помощью пакета reflect. Пакет reflect также может помочь вам вызвать произвольные функции, когда вы не знаете подпись во время компиляции.

Например:

func Map(f, v interface{}) interface{} {
    fn := reflect.ValueOf(f)
    fnType := fn.Type()
    if fnType.Kind() != reflect.Func || fnType.NumIn() != 1 || fnType.NumOut() != 1 {
        panic("Expected a unary function returning a single value")
    }
    res := fn.Call([]reflect.Value{reflect.ValueOf(v)})
    return res[0].Interface()
}

Это вызовет данную функцию f с аргументом v и вернет результат. Если v присваивается первому аргументу f, вызов будет успешным без паники. Вы можете поэкспериментировать с этим примером здесь: http://play.golang.org/p/kkBu56JYb8

Ответ 2

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

varForGenFunc := func(in interface{}) int {                             
                    fmt.Println("type of this object: ",reflect.TypeOf(in))
                    return 1}

TakeGenericFunc(varForGenFunc, variableForGen)

Исходя из этого, мы можем написать любые реализации func(interface{}) и передать их в качестве параметра TakeGenericFunc

Вы можете поиграть с этим здесь:

https://play.golang.org/p/f5UUhyhEx7u