#go #channel
#Вперед #канал
Вопрос:
У меня есть серверная часть (Go server), которая обслуживает несколько интерфейсов (веб-страниц), и все запросы / ответы обрабатываются через каналы определенных типов. Например, каждый интерфейс связан (на серверной части) с каналом, по которому отправляются ответы (type = chan<- Response).
Недавно я внедрил систему входа в систему, где каждый интерфейс связан с идентификатором пользователя. Для отслеживания пользователей у меня есть карта:
logins map[chan<- Response]LoginData
Используя это, я могу быстро искать вещи, связанные с интерфейсом, такие как разрешения. Все это работает нормально.
Однако, чтобы все было более безопасным и модульным, я перенес все элементы входа в систему в отдельный пакет. Все это работает, за исключением одной ошибки — карта логинов вводится с помощью типа «chan<- Response», но тип ответа определен в моем основном пакете, и я не хочу предоставлять его для пакета Login. (Я не думаю, что я мог бы в любом случае, поскольку это создало бы циклическую ссылку.)
Я только хочу использовать «chan<- Response» в качестве типа дескриптора в пакете входа — мне не нужно писать на этот канал оттуда. Я попытался преобразовать канал в небезопасный.Указатель, но это не разрешено компилятором. С другой стороны, я не могу использовать указатель на переменную канала (*chan<- Response) в качестве дескриптора, поскольку канал хранится в нескольких местах, поэтому переменная канала будет иметь разные адреса.
Я также пробовал выполнять приведение к другому типу канала, такому как chan int и chan interface{}, но компилятору это не нравится. Похоже, не существует никакого способа преобразовать канал в «универсальный» канал.
Мне действительно просто нужен адрес внутренних данных канала — как вы получаете при fmt.Выведите канал с помощью %v. Лучшее, что я могу придумать, это использовать строку, подобную этой:
var c chan<- Response = ...
var userID = "steve"
loginKey = fmt.Sprint(c)
Login.Add(loginKey, userID)
Я не уверен, что это допустимо, но, похоже, работает, но мне кажется, должен быть лучший способ.
Комментарии:
1. Вы могли бы использовать
interface {}
в качестве типа2. «тип ответа определен в моем основном пакете» — это недостаток дизайна.
main
Пакет должен делать как можно меньше, и он определенно не должен определять типы, именно по той причине, которую вы видите здесь.3. Спасибо @Adrian за чтение и понимание (а не за голосование «против», что, на мой взгляд, является разумным вопросом :). Я абсолютно согласен с вашим комментарием, но этот проект начинался как один основной пакет и рос. Я пытался разделить его части на внутренние пакеты (как в этом вопросе) Я прислушаюсь к вашему совету и попытаюсь разобраться, как переместить типы в отдельные пакеты.
Ответ №1:
С другой стороны, я не могу использовать указатель на переменную канала (*chan<- Response) в качестве дескриптора, поскольку канал хранится в нескольких местах, поэтому переменная канала будет иметь разные адреса.
Но это единственное (наполовину приемлемое решение): передавайте не chan Response
, а *(chan Response)
(добавляя указания по своему вкусу). Все остальное дерьмо. Лучшее, что можно сделать, это скрыть этот ответ канала в типе.
Комментарии:
1. Спасибо. Вы правы, должно быть достаточно просто иметь одну переменную chan и передавать указатель на нее. Это просто кажется немного избыточным, поскольку я думаю, что переменная канала по сути является просто указателем на реальный канал. Я согласен, что лучше всего создать новый тип, но нет смысла объявлять его в моем пакете входа, и я не могу объявить его в основном пакете (циклическая ссылка), поэтому, я думаю, мне нужно поместить его в новый пакет, который я импортирую в пакеты main и Login.