Блог* – Telegram
1.93K subscribers
3.48K photos
135 videos
15 files
3.71K links
Блог со звёздочкой.

Много репостов, немножко программирования.

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
#meme от коллег про контейнеризацию
😁24🤝2
Вопрос из 2011 года, но до сих пор эпично
🌚22🤡21🤯1😍1
#prog #go #article #suckassstory

В стандартной библиотеке Go есть тип http.Client — HTTP-клиент. Одно из полей этого типа — Transport. Это поле хранит значение, которое занимается обработкой единичных запросов. Разумеется, для поля Transport есть значение по умолчанию — DefaultTransport. Но есть одна загвоздка.

Поле Transport — и, соответственно, DefaultTransport — имеют тип RoundTripper. Это интерфейс с единственным методом:

RoundTrip(*Request) (*Response, error)


DefaultTransport при этом на самом деле является значением типа Transport, у которого бОльшая часть полей является конфигурацией. На практике часто требуется скорректировать конфигурацию по умолчанию под нужды приложения (например, поменять таймауты). Но как это сделать?

Так как в Go нет констант (кроме чисел и строк), DefaultTransport является глобальной переменной пакета http. Соответственно, чтобы не поменять глобальную конфигурацию для всего, что использует http.Client (включая, возможно, код в зависимостях), нужно сначала сделать копию этой конфигурации. Более того, так как DefaultTransport имеет тип интерфейса RoundTripper, сначала нужно привести его к конкретному типу Transport. В итоге на практике во многих проектах на Go есть код наподобие этого:

t := http.DefaultTransport.(*http.Transport).Clone()
// Change properties
t.TLSHandshakeTimeout = time.Second
t.DisableKeepAlives = true


Элемент синтаксиса .(*http.Transport) является кастом интерфейса к конкретному типу, и так как синтаксически это не форма каста, которая возвращает два значения, это "небезопасный" каст, который паникует, если тип отличается от указанного.

Какая по итогу ситуация? Во множестве реально используемых программ на Go есть код, который трогает глобальную переменную (и, так как это Go, без синхронизации), полагается на неявное обещание другого кода эту глобальную переменную не трогать и платят за проверки типов при касте, не смотря на то, что тип так-то известен статически. В теории тот факт, что DefaultTransport является интерфейсом, позволяет поменять реализацию в будущем. На практике из-за существующего кода этого никогда не произойдёт, потому что сломает кучу работающего кода. Поменять тип DefaultTransport также нельзя, потому что это будет ломающим обратную совместимость изменение.

Очевидным выходом из этой ситуации является добавить функцию, которая будет возвращать значение DefaultTransport, как конкретный тип Transport. Соответствующее предложение поступило в мае 2020 года, однако воз и ныне там.
👍11😁6
Подарок от ГМа
19🔥4🤮3🤡3💩2👍1