DEV: Рубиновые тона
3.22K subscribers
143 photos
2 videos
8 files
972 links
Анонсы новых видео о программировании (Ruby/Rails, Solidity/Ethereum, Python, JS и не только), практические советы, обзор полезных инструментов и новости из мира IT
Download Telegram
Последний наверное год-полтора мы периодически заходили в местную китайскую забегаловку с аутентичной едой и такой непринуждённой атмосферой лёгкой неприбранности. Моя жена сильно похожа на китаянку, так что мы в один момент как-то разговорились с владелицей заведения, и с тех пор каждый раз перетирали за жизнь. Конечно, на английском, хотя на базовом уровне она латышский тоже освоила. Да и я, сказать честно, не мастер в этом плане - хотя тут мне пеняют на то, что я и в русском ударению ставлю неправильно. Что поделать, мог бы вообще говорить с характерным акцентом.

Мне казалось, что имя Элайджа совсем простое, но нашей знакомой оно показалось каким-то сверх-сложным 😂 Помню ещё, я пытался провести аналогию с Элайджей Вудом - актёром из Властелина колец, но, оказывается, этот фильм совершенно неизвестен в Китае. Ну, я, как фанат Толкина, был уверен, что профессора знают по всему миру 🤓

Вообще, интересно подмечать, как всё-таки люди отличаются друг от друга, но всё равно могут найти общий язык. Поэтому, думается, стоит путешествовать, общаться с представителями разных культур. И поэтому, к сожалению, тоталитарные режимы пытаются оградить граждан от "тлетворного влияния". Потому что когда ты знакомишься с людьми "оттуда", ты понимаешь, что с ними вполне можно взаимодействовать...

К сожалению, с начала года, проходя мимо этого заведения, мы всё время видели за прилавком неизвестную девушку, кажется, местную. Раньше периодически "на хозяйстве" была дочка владельцев, но теперь и она куда-то исчезла. А на той неделе я с удивлением обнаружил, что на здании сменилась вывеска, и там теперь какие-то кебабы (kebabs, это шаурма). Искал в интернете какие-то сведения, ничего не нашёл. Странно, и жаль.

А тут ещё другие азиатские друзья - корейский ресторан - тоже переехал чёрт знает куда, только на велосипеде доедешь. Как-то всё разом 🤪

Это, конечно, в общем и целом пост наигранной весёлости, так как весёлого мало, но жаль, когда люди, с которыми ты, вроде, был в каком-то контакте, исчезают. https://www.youtube.com/watch?v=bsTxR64s5Kc
😢3👍2🌭1
В этом уроке мы поговорим о EIP2929 и EIP2930, о газе и его оптимизации. Мы узнаем, что такое холодное и горячее (hot/warm) обращение и почему это важно. Кроме того, мы узнаем, что такое accessList в транзакциях и как он может помочь заранее "разогреть слоты" для экономии газа. В конце мы используем этот подход в паттерне Extension. https://www.youtube.com/watch?v=RRXLzfUgcLE
🔥102👏1
К вопросу об указателях, в том числе и умных, в Rust

Система владения и заимствования в Rust, а также наличие разнообразных указателей может сильно запутать поначалу, особенно когда выясняется, что указатели бывают умные, а бывают - не очень. Это не говоря о том, что у нас есть referencing, а есть ещё dereferencing, и всё это вместо нужно как-то увязать. Попробуем разобраться.

Есть вот такой код:

let a = 5;
let b = &a;


a будет иметь тип i32, эта переменная "знает", где лежит число 5. Так как это простой тип данных, то число лежит в стеке. Кроме того, помним, что a "владеет" этим числом и в нужный момент должна удалить соответствующие данные.

В случае с b мы используем оператор referencing &, то есть фактически делаем указатель. Тип b будет &i32, эта переменная знает, у кого спросить, где находится нужное число (знает это а). При этом b не получает владение этим числом. Больше того, мы не можем даже сравнить а и b напрямую, код a == b; вернёт ошибку - типы разные, мы не можем сравнить само число i32 и указатель на него.

Однако никто не мешает нам сказать "дай мне то значение, которое лежит по этому указателю". Для этого используется оператор dereferencing, "звёздочка":

a == *b;


Теперь сравнение работает. Причём мы можем даже присвоить это значение другой переменной:

let mut c = *b;
c = c + 1;


Но значит ли это, что изменение c приведёт к измению a и/или b? На самом деле, нет. Мы опять же работаем с простым типом данных, и присваивание приводит к тому, что значение копируется для другой переменной, то есть a и c имеют разные, независимые значения.

С типами вроде vec и string ситуация похожая, но становится несколько сложнее.

let a = vec![1, 2, 3];


Мы создали вектор из трёх элементов, и мы знаем, что он будет хранится в heap, потому что потенциально его длина может меняться. В стек Rust может поместить только значения, размер которых точно известен во время компиляции, и вектор к такому типу (в отличие от фиксированного массива) не относится.

Но тогда вопрос: что же содержит в себе переменная a? Она по крайней мере должна знать, с какого адреса в heap начинается наш вектор и какой у него размер. То есть выходит, что это тоже какой-то указатель. Но "простой" указатель в духе &b данными не владеет, а просто ссылается на них. В нашем же случае мы явно ожидаем, что a владеет вектором, ведь кто-то же должен в итоге очистить память.

Ответ заключается в том, что vector (как и string) - это умный указатель, smart pointer, который действительно указывает на heap, но при этом владеет данными там и имеет пристыкованные метаданные.

Значит, если мы напишем

let b = &a;


то мы фактически тоже создадим указатель, который в свою очередь будет ссылатьcя на "умный указатель", и это, как говорится, две большие разницы.

К подобным типам данных тоже можно попытаться применить dereferencing, но вот такая строка выдаст ошибку:

let c = *b;


В отличие от простых типов данных, вектора и строки при присваивании не копируются, а переносятся. То есть к примеру вот такое

let a = vec![1, 2, 3];
let d = a;


приведёт к тому, что вектор "перенесётся" в d, ну то есть на него теперь указывает другая переменная. Когда же мы делаем let c = *b;, то мы фактически пытаемся через b влезть в данные a и сделать перемещение. Компилятору такой манёвр не сильно нравится, а скопировать весь вектор автоматом тоже не выходит, такую команду мы должны отдать сами:

let c = (*b).clone();


Это сработает, но мы именно полностью копируем вектор, он будет независим от вектора a.

Но тут можно задать новый вопрос - раз a тоже является указателем, можем мы сможем сделать dereferencing для него? Можно попробовать:

let b = *a;


Тип b определится как [i32], но программа не скомпилируется. Фактически мы пытается влезть напрямую в данные, на которые указывает умный указатель, и это получается просто массив. Массивы в Rust фиксированные и лежат в стеке, но Rust не может сунуть этот конкретный массив в стек, потому что неизвестна его длина в текущий момент времени!

Если вы думаете, что это всё, то ничуть не бывало. Есть ещё метод, который называется .deref():
👍6
let a = String::from("test");
let b = a.deref();


Тип b будет &str (если бы там был вектор, тип бы стал &[i32]). Чувствуете разницу? Этот метод сделает указатель непосредственно на данные, но он не попытается эти данные куда-то перенести. Если же перед deref поставить звёздочку, то мы опять получим ошибку: *(a.deref()), потому что опять будет сделана попытка вытащить сами данные из heap и куда-то их перетащить. Фактически, здесь *(a.deref()) равносильно *a.

При этом для простых типов deref не имеет смысла. На типах вроде i32 его нет вовсе, на указателях это метод просто вернёт сам указатель:

let a: i32 = 5;
let b = &a;
let c = b.deref();


Тип c будет &i32, как у b.

Интересно, что в ряде случаев Rust умеет делать dereference автоматически для нашего же удобства. К примеру, есть функция:

fn call(s: &str) {
println!("{}", s);
}


Она может принять как &str, так и String:

let a = "test";
let b = String::from(a);

call(a);
call(&b);


Работает это потому, что у String есть trait Deref (про него будет в видео), который умеет делать dereferencing в обычный &str.

То есть функция делает что-то такое:

let borrowed = &b;
let my_str = c.deref();


Тип my_str будет &str, то есть ровно то, что написано в функции. Хотя мы могли бы сделать слайс &str сами, это уж очень неудобно, ведь нужно получить сами данные из умного указателя, сделать заимствование, и потом создать слайс:

let borrowed = &b;
let my_str = &(*borrowed)[..];


А так deref() вызовется для нас, причём столько раз, сколько требуется, поэтому если функция принимает массив вида &[i32], то туда можно запихнуть и вектор с числами того же типа.

Теперь мы понимаем, какие есть указатели и как из них получать данные. Интересно, что мы можем создавать и свои умные указатели в Rust, и самым простым является Box - он положит наши данные в heap и сделает привязку к ним по аналогии с тем, что делает vector или string:

let a: Box<i32> = Box::new(42);


То есть наши число теперь торчит не в стеке, а в heap, и a содержит в себе умный указатель. Это значит, что мы можем тоже делать referencing и dereferencing:

let a: Box<i32> = Box::new(42);
let b: &Box<i32> = &a;
let c: &i32 = a.deref();
let d: i32 = *a;


Из аннотации типов можно легко видеть, где что получается. Кстати, *a тут тоже работает в отличие от истории с векторами и строками, потому что размер целого числа точно известен, его можно скопировать и поместить в стек. То есть в d будет число, независимое от того, на которое указывает a (там вообще выходит, что он сначала делает deref, потом звёздочку).
Однако вот так всё равно сделать нельзя: let e = *b;, как и в предыдущих примерах. *b укажет на сам Box<i32>, копировать его автоматом Rust не будет, так что там придётся написать clone()

Но тут вопрос: зачем нам вообще этот box нужен, если лучше хранить простые типы в стеке, который банально быстрее работает? Это так и есть, во многих случаях хранить обычное число "в коробке" смысла нет. Но если у нас есть данные, размер которых заранее неизвестен, то это может быть очень актуально.

К примеру, есть вот такая структура, описывающая кошку:

struct Cat {
name: String,
age: u8,
}

let cat = Cat {
name: String::from("Mr. Buttons"),
age: 3,
};


Где будет хранится наш Mr. Buttons? Сама структура будет в стеке, но строка как таковая будет в heap (в стеке же будет указатель на неё).

Однако предположим, что у кошки может быть предок, и это тоже кошка:

struct Cat {
name: String,
age: u8,
parent: Option<Cat>,
}


Можно ли такую структуру запихнуть в стек? Нет, потому что она рекурсивная, и её размер во время компиляции определить невозможно. Дело в том, что у Mr. Buttons может быть потомок, у того свой потомок, и так до бесконечности. Поэтому родителя нужно хранить в heap, и это тот случай, когда нам нужен Box:

struct Cat {
name: String,
age: u8,
parent: Option<Box<Cat>>,
}


Создадим двух кошек:
👍5
let cat_parent = Box::new(Cat {
name: String::from("Parent Cat"),
age: 3,
parent: None,
});

let cat = Cat {
name: String::from("Mr. Buttons"),
age: 3,
parent: Some(cat_parent),
};


Можно сделать так, можно было первую кошку сделать без Box, и добавить Box::new только для parent у Mr Buttons.

Но с таким подходом есть проблема: cat_parent будет недоступен после создания Mr Buttons, тк там происходит move (перемещение). Вместо этого можно сделать clone: parent: Some(cat_parent.clone()),. Это, правда, может быть не сильно оптимально, так как мы копируем всю структуру сразу, плюс фактически родитель для Mr Buttons и Parent Cat не связаны между собой (изменение возраста Parent Cat не приведёт к изменению возраста родителя).

Можно попробовать добавить заимствование для родителя, но тогда придётся прописывать lifetimes. Если же мы хотим, чтобы родитель был связан с существующей кошкой, плюс к тому, изменения кошки приводило бы к изменению родителя, то нам потребуется использовать другие умные указатели. Их мы рассмотрим в следующем уроке.
👍5🔥31🤯1
Знаете, я тут занялся некоторым "обновлением" своего сайта, которое в итоге свелось к принципу "отсекаю всё лишнее". В итоге, решил в принципе перевести сайт на Hugo, отказавшись от Ruby on Rails, и уйти на Firebase с Heroku, которые всё равно прикрыли бесплатные тарифы, да и вообще какие-то странные вопросы стали задавать.

Пока выходит так https://github.com/bodrovis/bodrovistech В целом, на данный момент мне требуется только возможность иногда публиковать посты, ничего больше - это раньше там были комменты, админка, возможность добавлять песочницы, целая батарея тестов и прочее. Наверное, когда этот сайт писался изначально, а было это лет 12 тому назад, это в какой-то мере требовалось, но теперь для всего есть сервисы.

Честно говоря, я даже весь JS убрал в принципе, дабы ускорить загрузку. Минимализм во все поля. К Hugo вообще советую присмотреться, если требуется не сильно сложный сайт, у меня на нём вот уже два ресурса крутятся
👍161❤‍🔥1🌚1
Achievement unlocked. P.S. И вновь: наш чат живёт здесь https://t.iss.one/joinchat/MxYT6-01eeA1NTYy комментарии пишутся через него, анонимные комментарии я не могу открыть, там сразу начинает валиться спам, к сожалению
👍17🔥6🎉21
Знаете, подумалось тут. Когда-то очень давно, когда я ещё учился в институте, которого уже не существует, мы ведь все были совершенно нищие ("отличная" сессия помогала мало, прибавка стипендии была смешная), за работу на кафедре платили копейки. Но тогда как-то было повеселее, что ли. Сейчас вроде бы относительный достаток, но... Как это было в шутке. Сначала 11 друзей Оушена, потом 5 друзей Оушена, потом 2, а потом Оушен пьёт в одиночестве. https://www.youtube.com/watch?v=dwiAaLKuLuY&list=RDEMVxwqrWcBmdip7J7_ymuGTQ&index=4
👍8😢61
Забавно. Я сейчас вспоминаю детство - я вообще очень хорошо себя помню маленьким (к сожалению, некоторые взрослые ведут себя так, как будто им всегда было лет по 40 минимум). Тогда как-то казалось, что "всё дорого". Ну, все более-менее хорошие штуки - это только для богатых дядек с пузом и в дорогих пиджаках. Кажется странным, но в какой-то момент я точно помню, что в ресторане Friday's (только открывшимся) все цены были в долларах, так что я растягивал один "детский" коктейль на целый вечер, чтобы не дай бог не заказать лишнего. Теперь-то в этот Friday's и ходить не сильно охота, нет там ничего такого, обычный американский фаст-фуд, только overpriced. А тогда это был супер-круто, событие, происходящее раз в несколько месяцев.

Тогда Советский союз уже приказал долго жить, но эти отголоски доносились ещё очень долго...

Практически с молоком матери впитано это странное ощущение, когда не было детского питания, банальных предметов гигиены, когда дед постоянно пропадал на каких-то непонятных "усилениях", потому что повсюду был бардак и беспредел... Я почти не помню, что происходило, к примеру, во время обстрела белого дома, но потом спустя много лет я довольно долго встречался с девушкой сильно старше меня, так что ради интереса спросил - какие вообще были мысли тогда? "Да никакие, мы на даче торчали" - вот и весь ответ. Для многих это прошло мимо.

Примерно в то же время были страшные события и здесь, в Латвии. Тут вообще сильно не любят того же Горбачёва, который приказал разгонять протесты силой. Тут до сих пор остались мемориалы сопротивлению... Тяжелое, тёмное время в стране, которая натерпелась всякого.

Людям с постсоветского пространства, то есть большинству из нас, это всё понятно без слов, но вот коллегам из других стран я никогда не мог по-нормальному это всё объяснить, почему-то не получается. Начинаешь говорить, а слов не находишь, а если находишь, то не те. Вроде было это всё, а как будто и не по-настоящему, и как будто не с тобой. Другая жизнь, другое время.

Вообще, этих "других жизней" было неожиданно много, буквально каждые лет пять что-то новое и неожиданное. Как это было у Тэффи: "вся минувшая жизнь острым зигзагом пронеслась перед моим внутренним взором: детство, первая любовь… война…". Послушайте, кстати, эту аудиокнигу, я её полностью начитал на YT - спустя сто лет она оказывается весьма актуальной. Ну, так и тут - вспоминаешь, и понимаешь, что был тогда совершенно другим человеком. Первый напечатанный рассказ, первая записанная композиция, первая любовь, первое предложение руки и сердца, первая "смена вех".

У вас не было такого, что будучи совсем ребёнком вы спрашивали самого себя: "а каким я буду спустя 10, 20 лет?". У меня есть одно такое воспоминание, которое неожиданно похоже на сцену из игры chrono cross - саундтрек, исполненный нами в иной вселенной, я прилагаю. Да, помню то время неплохо - я был таким пухлым пацаном, который не верил (или уже не хотел верить) в то, что у тебя могут украсть, что тебя могут обмануть. Потом жизнь отрезвила, что говорить. Смотря в зеркало, сложно увидеть того парня. Помните, как это было у Семёновой - "на него смотрел закоренелый каторжник". Каторжник или нет, а, во всяком, случае, некто весьма недоверчивый. Интересно, а как у вас, дорогие друзья?

В те годы мы с моим лучшим другом думали, что вырастем, будем жить рядом, наши жёны будут лучшими подругами, наши дети будут вместе играть. К этому моменту мы знакомы уже... господи, 28 лет. Некоторые столько не живут. Но мой товарищ так и не обзавёлся женой, да и с детьми напряжёнка у нас обоих. Мы спорим, ведь у него "не всё очевидно" (какой-то идиот на работе наговорил ему бреда), нас разделяет тысяча километров и не похоже, что мечта осуществится. Наверное, каким-то мечтам лучше так и оставаться мечтами.
32👍4🙏2
Зачем я всё это пишу? Честно говоря, я не знаю. Я также не знаю, как ответить на вопрос - зачем ты вообще этим всем занимаешься? Точнее, у меня есть один ответ, и его дал пан Сапковский. "Tutaj przynajmniej zebrali się tacy, z którymi mam o czym rozmawiać. Tacy, którzy nie przerywają rozmowy, gdy podchodzę. Tacy, którzy nawet nie lubiąc mnie, mówią mi to w oczy, nie rzucają kamieniami zza opłotków. Jadę z nimi z tego samego powodu, dla którego pojechałem z tobą do flisackiej oberży. Bo jest mi wszystko jedno".

Потому что тут есть люди, с которыми можно поговорить. Да, они могут быть не согласны, но они не гонят прочь и не говорят - "ты какой-то странный, наркоман, наверное". А ещё просто потому, что нужно ведь что-то делать, и это занятие ничуть не хуже других. Остальное можно понять из текста выше, либо просто перевести, там простой язык.

Берегите себя, скоро увидимся.

https://www.youtube.com/watch?v=NfWbTEr5pYo
39👍3🙏31
У нашей школы тут небольшая партнёрка планируется с Blast (да, мы про них говорили в контексте лицензии), они вроде хотят проспонсировать курс на английском. Судя по всему, у них запуск самой платформы L2 буквально сегодня ночью, там есть вариант получить airdrop. Я и подумал залететь на небольшую сумму просто ради интереса. Если есть желание, вот инвайт blast.io/Z1F04, можно https://blast.io/en/airdrop тут погасить. Там правда нужен твиттер и дискорд. Это не реклама
👾61👍1
Всё, Blast в mainnet. Ещё три инвайта есть blast.io/P65PH blast.io/06DI7 blast.io/A90IS
4👍1👎1😁1
Кстати, у нас тут явление Ленина, можно послушать (с неповторимым прононсом и неправильными ударениями, согласно общему мнению зрителей) https://www.youtube.com/watch?v=okhCJLrGi8I Вообще, довольно любопытно вышло. Правда, жаль одно - Ленин набрал какое-то безумное количество часов просмотров всего за пару дней, даже относительно "хитовый" урок про ownership, загруженный ещё в ноябре, проигрывает примерно на треть. Вот что Ильич делает.
👍3😱1🤷1
Сегодня стрим, и мы отправляемся на собеседование. Возьмём несколько десятков вопросов средней сложности, которые были опубликованы в 2024 году. Постараемся ответить на них максимально коротко, но при этом разобраться, почему это правильный ответ. https://youtube.com/live/h-ysFQUlE_w?feature=share
👍15🔥5
Хоть chat gpt подбодрит 😂
7😁1