вызвать функцию, которая принимает «chan interface{}»

#go #casting #channel

#Вперед #Кастинг #канал

Вопрос:

Для людей, которые проголосовали против этого вопроса — у него есть законный ответ, который является отражением (см. Ниже).

Я хочу создать универсальную функцию, в которой я могу передать ей любой канал, и она сообщит мне, какая часть его емкости заполнена. Меня раздражает, что мне приходится переводить канал в «chan interface {}».

Мой вопрос в том, что для функции foo , приведенной ниже, я могу передать ей строку, и это нормально. Go принимает это как интерфейс{}. Почему она не ведет себя одинаково для каналов? Могу ли я создать функцию, которая принимает универсальный chan interface{} ?

 func testFoo() {
    str := "anything"
    foo(str)  //This is fine.
    aChan := make(chan string, 10)

    //This line doesn't compile.  Can I avoid casting to chan interface{}?
    CheckChanLen(aChan) 
}

func foo(obj interface{}) {}

func CheckChanLen(aChan chan interface{}) {
    chanCap := cap(aChan)
    chanLen := len(aChan)
    fmt.Printf("len:%d cap:%d", chanLen, chanCap)
}
  

Комментарии:

1. Вы не можете, составные типы в Go не являются ковариантными.

2. Вы можете передать a string функции, принимающей an, interface{} потому что string выполняется interface{} . Тип параметра канала — chan interface{} ; это конкретный тип, а не интерфейс. Никакой другой тип не может «выполнить», chan interface{} потому что это не интерфейс, поэтому вы можете только передать chan interface{} ему, больше ничего.

3. В Go вообще нет кастинга, поэтому, что бы вы ни делали, вы избежите «кастинга в chan interface{}».

Ответ №1:

Короткий ответ: нет.

chan interface{} отличается от interface{} .

interface{} является универсальной для всех типов, но chan interface{} не является универсальной для всех chan типов.

Дженерики предоставят эту возможность, но их нет на языке go (пока).


Если все, что вам нужно сделать, это проверить пропускную способность / длину канала, вы можете использовать reflect пакет следующим образом:

 import "reflect"

func CheckChanLen(aChan interface{}) {
        rv := reflect.ValueOf(aChan)
        if rk := rv.Kind(); rk != reflect.Chan {
                panic("expecting type: 'chan ...'  instead got: "   rk.String())
        }           

        chanCap := rv.Cap()
        chanLen := rv.Len()
        fmt.Printf("len:%d cap:%dn", chanLen, chanCap)
}
  

Комментарии:

1. Вероятно, это правильный ответ, и я с нетерпением жду появления дженериков (спасибо за ссылку). Я собираюсь подождать несколько дней, прежде чем отмечать ваш ответ принятым в надежде, что у кого-то есть умная идея.

2. Понятно. Я столкнулся с этой точной проблемой пару месяцев назад, когда писал общий разделитель каналов. Поскольку я уже использовал отражение, не составляло большого труда убедиться, что interface{} ввод пользователя имеет chan базового типа — но это, конечно, была проверка во время выполнения, а не проверка во время компиляции, как вы ищете.

3. Это правильный ответ на конкретный вопрос OP. Однако вопрос OP, похоже, является проблемой XY (как и примерно 99,9% вопросов, на которые отвечают дженерики — таким образом, мой страх за день Go поддерживает дженерики). Если OP подробно расскажет о своей фактической цели , я уверен, что кто-нибудь сможет придумать умное решение для этого .