#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 подробно расскажет о своей фактической цели , я уверен, что кто-нибудь сможет придумать умное решение для этого .