LINUX.ORG.RU

Вопрос по Rust

 


0

3

Как сделать что бы это скомпилировалось?

struct A {
    b: B,
}

struct B;

impl B {
    fn fun(&self, a: &mut A) {
        println!("OK");
    }
}

fn main() {
    let mut a = A{b: B};
    a.b.fun(&mut a);
}

Ссылка на playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5247385ca0f8473e46d6d91112059dce

Ответ на: комментарий от alysnix

это стало повальной болезнью всех новомодных язычков

Угу, например в C++ уже была такая мода (везде this->) когда ни раста ни го даже в проекте не было, он (C++) как раз был новомодным второй раз (когда румынский вампир всех покусал).

anonymous
()
Ответ на: комментарий от alysnix

это на стеке переменная инициализируется некой структурной константой через копирование?

Через перемещение как и новых C++, в релизном асме скорее всего будет присваивание полей тупо на месте в обоих языках.

anonymous
()
Ответ на: комментарий от alysnix

конструкторы в русте есть?

Как в с++ нет, но есть аналоги, статические методы, ну и рекомендации называть основной «конструктор» «new» и для «конструктора» без параметров реализовывать трейт default (для простых типов тупо приписать макрос #[derive(Default)] к структуре). С одной стороны немного теряется гибкость C++,(реально не хватает не конструкторов как таковых, а placement new), но в обмен весь этот геморрой с правилами трех, правилами пяти, виртуальными деструкторами отсутствует, что по моему большой плюс.

anonymous
()
Ответ на: комментарий от SyntaxError

И вообще код который вызывается не явно это не очень хорошо.

а мув семантика в инициализации это не скрытый код? а источник в таком присваивании вида {field1 = 10, field2 = x} это откуда берется? это надо иметь лишнюю зарезервированную область памяти, выставлять там поля в указанные значения(потому что тут не константа), а потом делать битовую копию в декларируемую переменную. тут скрытого кода даже больше, чем у с++ с прямым конструктором, что просто по адресу обьекта лупит значения полей.

то есть в чем разница - си++ конструктор работает с адресом нового обьекта, а в расте - обьект сначала конструируется в одном месте(судя по грамматическому правилу с присваиванием), а потом присваивается в целевой обьект. это и дольше и кода больше. с си++ так тоже можно делать, но это считается плохим стилем.

чтобы в расте сделать как в си++, видимо или придется вводить конструкторы или делать хак в компиляторе, что будет такие вот инициализации обьектов присваиванием генерить, как будто там inplace инициализации. но подобные хаки вопиют об изьяне в языке ващета

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

еще в русте кучеряво выглядит написание «метода» с явным селфом, что уважающий себя с++ (например) опускает за ненадобностью.

Это вы, похоже, про deducing this из C++23 еще не знаете. Даже C++у хочется быть новомодным.

eao197 ★★★★★
()
Ответ на: комментарий от alysnix

чтобы в расте сделать как в си++, видимо или придется вводить конструкторы или делать хак в компиляторе, что будет такие вот инициализации обьектов присваиванием генерить, как будто там inplace инициализации. но подобные хаки вопиют об изьяне в языке ващета

В C++ как раз этот хак и есть для кода вида:

auto x = X();

тоже никакого вызова оператора присваивания не будет, вызовется только конструктор.

anonymous
()
Ответ на: комментарий от alysnix

а мув семантика в инициализации это не скрытый код? а источник в таком присваивании вида {field1 = 10, field2 = x} это откуда берется? это надо иметь лишнюю зарезервированную область памяти, выставлять там поля в указанные значения(потому что тут не константа), а потом делать битовую копию в декларируемую переменную. тут скрытого кода даже больше, чем у с++ с прямым конструктором, что просто по адресу обьекта лупит значения полей.

Ничего этого не нужно let в rust это не присваивание из C++ а тупо привязка имени к готовой области памяти https://doc.rust-lang.org/std/keyword.let.html

anonymous
()
Ответ на: комментарий от anonymous

а тупо привязка имени к готовой области памяти

а это тоже привязка имени к готовой области памяти???

let x = 5

вы уж разберитесь там. нигде в ваших ссылках не говорится что это «привязка имени».

alysnix ★★★
()
Ответ на: комментарий от anonymous

тоже никакого вызова оператора присваивания не будет, вызовется только конструктор.

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

alysnix ★★★
()
Ответ на: комментарий от anonymous

но оптимизатор имеет право выкинуть такое выделение памяти.

как можно выкинуть, если вы берете тут адрес от константы? что это такое адрес числа в русте? у нуля есть адрес? смело!

alysnix ★★★
()
Ответ на: комментарий от alysnix

что лишь подтверждает мои слова, что в таком случае нужен хак.

Не нужен let в rust тупо привязка (binding) имени к выражению, это не присваивание. Все это имеет корни из ocaml https://www2.lib.uchicago.edu/keith/ocaml-class/definitions.html и в расте все так и осаталось, включаея и паттерн матчинг для let, и затенение, разве от что рекурсивного let отказались

anonymous
()
Ответ на: комментарий от anonymous

вы путаете небось с тем случаем, когда обьявляется «переменная» без mut, что по факту есть просто констатна. тогда ей память просто не нужна, и потому имя константы можно рассматривать как тег выражения.

я же имею ввиду, когда обьявляют нормальную переменную. под нее нужно место, ибо она будет меняться. у меня ошибка в том, что я забыл, что в русте везде надо понавтыкать mut, ибо все констатное по дефолту. кстати спорное решение.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

как можно выкинуть, если вы берете тут адрес от константы?

Чуть опечатался должно было быть &x а не &5, но так тоже хорошо получилось :)

что это такое адрес числа в русте? у нуля есть адрес? смело!

А почему нет? Ссылки растовские же более явные чем в С++, неявное разыменование там только через операторы, и при прямом использовании нужно явно разыменовывать.

let y = &x;
assert!(x == *y);

и для передачи в функции принимающие ссылки тоже нужно явно прописывать &, и получается очень удобно также передавать и литералы. В с++ для этого пришлось вводить неявное создание переменных для const T & параметров. Вот такое

int add1(int &x)
{
return x + 1;
}
 
int main()
{
add1(123);
}

же не соберется, а если добавить const то соберется, в раст все более прозрачно и оба варианта рабочие:

fn add1(x: &i32) -> i32 {
    *x + 1
}

fn add2(x: & mut i32) -> i32 {
    *x + 2
}

fn main() {
    add1(&123);
    add2(& mut 123);
}
anonymous
()
Ответ на: комментарий от alysnix

вы путаете небось с тем случаем, когда обьявляется «переменная» без mut, что по факту есть просто констатна. тогда ей память просто не нужна, и потому имя константы можно рассматривать как тег выражения.

Через let (как впрочем и через const в С++, но там запутаннее из-за долгой эволюции конечно) настоящие константы которые можно использовать в compile time не объявляются (это только через const в rust). А через let только «неизменяемая переменная» (хоть это и оксюрмон, но функциональщики заставили и к такому привыкнуть). mut тут ничего ни добавит ни убавит, что с ним что без него все одинаково.

anonymous
()
Ответ на: комментарий от alysnix

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

Примерно такой же бред можно написать и про ++. Ну т.е. любой компилятор видя x += 1 имеет право выпустить ассемблерную команду инкремента, чисто чтоб место под константу не тратить, и он даже иногда может так заменить x += y, если вывел что y == 1, но только в волшебном C есть правильный ++, чтоб можно было обойтись без «хака», как реальный пацан.

Однако раст проектировали люди в 21 веке, когда никто не ждёт необходимости водить компилятор за ручку, поэтому вместо «оптимальных» инструкций сделали общие, а уж о том, конструировать на месте или копировать думает компилятор.

khrundel ★★★★
()
Ответ на: комментарий от alysnix

зачем в хрусте писать запятую после последнего поля в структуре?

Эээ….

Ты как бы только растом интересуешься?

Такую хрень добавили примерно в каждом первом современном языке. Вот в тот момент, когда люди начали пользоваться системами контроля версий, особенно командами типа diff/blame, они поняли, что удобно иметь опциональную запятую в конце списков, чтоб не менять строку, которую не меняешь по факту. Альтернативой было бы форматирование вида

 a
,b
,c
,d

Что уж совсем уродство.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Ну т.е. любой компилятор видя x += 1 имеет право выпустить ассемблерную команду инкремента

не тот случай. тут фронтенд скажет бекэнду на некоем абстрактом протоколе add (var(x), const(1)). а бекенд видя, что что второй параметр - константа да еще и единица, немедля испустит команду инкремента вместо обычной суммы. это наивная оптимизация которая очевидна и есть везде.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

не тот случай. тут фронтенд скажет бекэнду на некоем абстрактом протоколе add (var(x), const(1)). а бекенд видя

Самый что ни на есть тот, который происходит когда компилятор начинает в оптимизацию.

И превратить let f = foo() в заполнение на месте тоже большого ума не надо, особенно если компилятор и так foo собирался заинлайнить. В случае, когда заинлайнить нельзя, подойдёт let f; foo_inplace(&f) что ненамного сложнее.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

я вот вообще считаю аргумент с diff вздорным. нельзя делать грамматику языка, имея в голове левые тулзы, которые возможно умрут со временем, или не будут применяться вообще.

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

в реальности правят много, и какая-то убранная запятушка в одном из множества мест погоды не делает.

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

зы: опять же теперь если случайно удалится последний элемент, компилятор этого не заметит.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

зы: опять же теперь если случайно удалится последний элемент, компилятор этого не заметит.

Значит этот элемент больше нигде не используется, кек. Иначе ошибка компиляции.

cumvillain
()
Ответ на: комментарий от alysnix

я вот вообще считаю аргумент с diff вздорным. нельзя делать грамматику языка, имея в голове левые тулзы, которые возможно умрут со временем, или не будут применяться вообще.

Твоё мнение очень важно для нас. В реальности же работа с соурсконтролем важна как ничто другое.

Вот видишь ты в енуме элемент mode3 и тебе интересно, что это вообще. Делаешь аннотейт, узнаёшь в каком коммите он был добавлен. Смотришь дифф… А там написано, что в коммите появился mode4, а в строчку с mode3 просто запятую добавили.

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

Во-первых, не только удаляют, но и добавляют. Если в стиле вашего проекта прописано, что надо ставить в конце запятую то будут ставить и норм. Во-вторых, не только в енуме, но и в списочном инициализаторе, в массиве например. Такое очень часто добавляется. В третьих, почему ты вспомнил структуру? В C/C++ точки с запятой после полей структуры обязательны, в том числе и после последнего. То что в данном контексте один знак препинания заменяется другим разве что-то принципиально меняет?

в реальности правят много, и какая-то убранная запятушка в одном из множества мест погоды не делает.

Ещё раз, внимательнее: во всех современных языках сделали так. Это можно сказать промышленный стандарт сейчас. Если бы ты сейчас делал свой ЯП тебе пришлось бы делать так просто по факту что люди ожидают такого от нового языка и если ты так не сделаешь, то тебя будут доставать просьбами добавить. Это как точка с запятой в паскале, уж сколько Вирту нравилась идея разделителя инструкций, но людей так задолбала необходимость ставить/убирать её при добавлении/удалении дебаговых инструкций, что в конце концов во всех нормальных реализациях её сделали опциональной.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

В третьих, почему ты вспомнил структуру?

посмотри первую декларацию в топик старте уже.

Ещё раз, внимательнее: во всех современных языках сделали так.

я часто пишу параметры вертикальным списком у функций. типа

some_type my_func(
  jfkdjfkdjf::jjfkdjfkj par0, ///...
  kjhbbncbvnxbcv par1,  ///...
  nnnfds::kkgflkgfd par2  /// ...
)

и возникает тот же «эффект запятой». в списках параметров «все современные языки» тоже дают возможность лепить запятую в конце? или список параметров - это уже не список? или со списком параметров не работает diff?

в вызове функции тоже список актуальных параметров, там можно запятую поставить-то?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от cumvillain

Значит этот элемент больше нигде не используется, кек.

если в данном контексте нет ошибки - это лишь значит, что на данный момент в данном контексте все вроде выглядит неплохо… но полуторачасовая сборка кода может не завершиться вообще говоря

alysnix ★★★
()
Ответ на: комментарий от alysnix

посмотри первую декларацию в топик старте уже.

Меня не интересует первая декларация в топикстарте. Там никаких проблем нет. Меня интересует, почему ты на неё триггернулся, если в твоём любимом C то же самое, только вместо запятой точка с запятой.

я часто пишу параметры вертикальным списком у функций. типа … и возникает тот же «эффект запятой». в списках параметров «все современные языки» тоже дают возможность лепить запятую в конце? или список параметров - это уже не список? или со списком параметров не работает diff?

Хороший вопрос, давай посмотрим:

fun main() {       
    println("Hello, world!!!",) // работает
    // println("Hello, world!!!",,) // не работает
}

Прикинь, да, в котлине работает. Но, заметь, если бы и не работало, мало ли какие тараканы в голове, это не повод говорить «сгорел сарай - гори и хата», если авторы какого-то языка считают, что «это другое», ну как бы печально, но спасибо хоть в инициализаторе массива оставили

khrundel ★★★★
()
Последнее исправление: khrundel (всего исправлений: 1)
Ответ на: комментарий от khrundel

Прикинь, да, в котлине работает.

котлин - не наш выбор. лучше приведи список «современных языков», где можно и параметры функции запятой вот так огораживать.

alysnix ★★★
()
Ответ на: комментарий от khrundel

Меня не интересует первая декларация в топикстарте. Там никаких проблем нет.

ой-ейейейейейей!

у него стоит запятая после декларации поля.

struct A {
    b: B,
}

и они так везде ставят, прям как традиционную точку с запятой, которая означает - «конец текущей декларации». а запятая означает - «а теперь следующий элемент последовательности, господа!»… а его то и нет.

alysnix ★★★
()
Ответ на: комментарий от khrundel

Это как точка с запятой в паскале, уж сколько Вирту нравилась идея разделителя инструкций…

точка с запятой обозначает конец текущего синтаксичского правила, и ставится для того(в том числе), чтобы компилятор пропускал ошибочное правило до этого символа и продолжал парсинг дальше. чтобы при первой же ошибке не сходить с ума… а не потому, что Вирту нравилось.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

точка с запятой обозначает конец текущего синтаксичского правила, и ставится для того(в том числе), чтобы компилятор пропускал ошибочное правило до этого символа и продолжал парсинг дальше

Питон с хачкелем справляются без всей этой срани. И гоголанг тоже, кстати.

cumvillain
()
Последнее исправление: cumvillain (всего исправлений: 1)
Ответ на: комментарий от cumvillain

голанг точки с запятой имеет, а опускать их можно койгде потому, что сам их автоматически ставит в конце строк при компиляции, отчего его ситаксис слегка чудесат… что лишь подтверждает то, что я сказал.

а пытон вообще интерпретатор. хачкел не ел, не знаю.

alysnix ★★★
()
Ответ на: комментарий от alysnix

у него стоит запятая после декларации поля.

Малышева.jpg.

В чём проблема-то? То что не как в си?

они так везде ставят, прям как традиционную точку с запятой, которая означает - «конец текущей декларации». а запятая означает - «а теперь следующий элемент последовательности, господа!»… а его то и нет.

Побойся бога. Вирт месяц назад преставился, ещё 40 дней не прошло, душа его среди нас бродит, а ты имеешь наглость втирать про то что точка с запятой - это «конец инструкции/декларации».

Вот, код из википедии по одному из последних его язычков, оберону:

MODULE Figures; (* Abstract module *)

TYPE
   Figure*    = POINTER TO FigureDesc;

   Message*   = RECORD END;
   DrawMsg*   = RECORD (Message) END;
   ClearMsg*  = RECORD (Message) END;
   MarkMsg*   = RECORD (Message) END;
   MoveMsg*   = RECORD (Message) dx*, dy* : INTEGER END;

   Handler*   = PROCEDURE (f : Figure; VAR msg : Message);

   FigureDesc* = RECORD
      (* Abstract *)
      handle : Handler;
   END;

PROCEDURE Handle* (f : Figure; VAR msg : Message);
BEGIN
   f.handle(f, msg)
END Handle;

Обрати внимание: структура moveMsg не содержит точки с запятой перед END, а FigureDesc, с многострочной декларацией, содержит. Видимо уже тогда последняя была опциональной и ставилась при многострочной декларации. При этом в конце процедуры, после f.handle(f, msg) точки с запятой нет. Это, видимо, дань уважения Вирту, который долго участвовал в сраче на тему нужно ли ставить точку с запятой после последней в блоке инструкции. Поэтому настоящие паскалисты не ставят. Ненастоящие придумали отмазку в виде «пустой инструкции», т.е. ‘;’ остаётся как бы разделителем, просто за ней идёт пустая инструкция.

Это как раз логично для раста, где блок {let a = 0; foo(&a)} возвращает то что вернула foo, а блок {let a = 0; foo(&a);} возвращает unit. Если принять правила «результатом блока является последняя инструкция» и «точка с запятой - разделитель инструкций» то такое поведение будет следовать из правила. Ну и с запятой аналогично, единственное что понадобится уточнение, что игнорируется только стоящий в конце списка пустой элемент.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

https://online.oberon.org/oberon_en#sec63

судя по грамматике оберона по поводу record:

 RecordType   =  RECORD ["(" BaseType ")"] [FieldListSequence] END.
 BaseType     =  qualident.
 FieldListSequence  =  FieldList {";" FieldList}.
 FieldList    =  IdentList ":" type.
 IdentList    =  identdef {"," identdef}. 

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

зачем в хрусте писать запятую после последнего поля в структуре?

В чём проблема? Много где этим пользуются с давних времён.

A definition that included bus-specific fields would look like (using the eepro100 driver again):

static struct pci_driver eepro100_driver = {
       .id_table       = eepro100_pci_tbl,
       .driver               = {
              .name           = "eepro100",
              .bus            = &pci_bus_type,
              .probe          = eepro100_probe,
              .remove         = eepro100_remove,
              .suspend        = eepro100_suspend,
              .resume         = eepro100_resume,
       },
};

Some may find the syntax of embedded struct initialization awkward or even a bit ugly. So far, it’s the best way we’ve found to do what we want…

https://docs.kernel.org/driver-api/driver-model/driver.html

Ну а с точки зрения Rust, это просто дефолтное поведение при автоформатировании кода.

AlexVR ★★★★★
()