几年前,作为一名年轻的“来自铁锈地带”的人,你梦想成为一名系统程序员,如果你愿意的话,可以成为一名深渊观测者。你想通过尽可能接近金属来生存、呼吸和死亡。您成长在这样一个严酷的环境中:阅读汇编输出以删减几条指令,试图编写最快的代码、段错误和文档不完整的硬件,所有这些都是为了成为一名系统程序员。你深情地回顾那些年,因为它把你变成了今天的程序员。一个无与伦比的深渊凝视者,一个精灵,一个让凡人恐惧和崇拜的人,你给这个支撑着这个世界的基础的世界带来了密码。今天你是应一位朋友的要求来面试的,应聘的是一位生锈公司的职位。他们希望能够雇佣你,这样你就可以将红宝石菲利斯的意志导入所有从你手指间飞出的代码中去。他们当然不能就这样给你这份工作。关于你的技术的传言是不是真的,你未来的潜在同志必须亲眼看看是不是真的。你看着你的面试官,他会问你是否准备好开始了。你点点头,准备好承担任何交给你的任务。
给你一个大小为n+1的数组,整数为0到n。使用针对大小进行优化的算法和针对大O优化执行的算法在列表中查找重复项。面试官解释说,请确保只使用Rust的稳定版本,因为我们在这里不是每晚都用到它。";你的面试官解释说,你的面试官解释说,你可以使用一个大小优化的算法和一个针对大O优化执行的算法在列表中查找重复项。如果我在O(1)中只做一个既能做两件事又能做的算法有关系吗?";你会问。面试官困惑地看着他们的笔记,因为这不是他们被告知可能的答案之一。他们是一名年轻的工程师,你正在接受主要工程职位的测试。令人高兴的是,你已经能够证明你可以做好你的工作,教那些在资历方面比你低的人。";嗯,当然可以。他们说,如果你能呃证明这一点的话。
你拿出你的MacBook,充当与沃兹尼亚克本人联系的渠道,这样他就可以像他以前多次做过的那样引导你。你清空了自己,成为那些凝视着你面前深渊的人的器皿。让我们从创建一个项目来容纳召唤开始吧。你会说,一定要解释你的流程。面试官微微点点头,但他们似乎比之前更警惕了。也许召唤不是合适的词。也许是咒语?无论采用哪种方式,您都可以像所有Rustaceans一样在控制台上输入魔术单词,重新开始世界的意愿之前、现在和之后。
好的,让我们设置我们的货单,将高质量的手工制作的代码发送给我们的最终用户。";您打开Cargo.toml文件,并在其中填入您根深蒂固的优化咒语。
[Package]名称=";访谈";版本=";0.1.0";作者=[";Z̴̧̡̢̨̛A̷̡̡̢̢̡L̶̢̧̢̪̬Ģ̵̡̢̢̧̛Ơ̵̵̡̡̡̧̢̛̬͇̬̳Ċ̷̢̨̢̼̰Ǫ̷̨̧̢̛͎M̵̡̨̖̹̣E̴̢̧̨̨̛S̸̱̠̹̮̣<;Z̴̧̡̢̨̛A̷̡̡̢̢̡L̶̢̧̢̪̬Ģ̵̡̢̢̧̛Ơ̵̡̡̬͇̬truecodegen=";2018";[dependencies][profile.release]panic=";̶̢̧̢̪̬Ģ̵̡̢̢̧̛Ơ̵̡̡̬͇̬";lto=truecodegen-unit=1opt-level=";s";
“等等,你的名字怎么了?”面试官问道。你把它们挥到一边回答说,不要担心,甜美的夏日孩子,免得你像我一样被诅咒。重要的是,我们已经针对代码生成大小进行了优化,并从代码中尽可能多地剔除了不必要的汇编指令。他们问道,这并不意味着你应该使用z来表示大小。";什么?并在输出中添加一条完全无用的指令?我不这么认为。";
您可以快速打开编辑器以访问src/main.rs。你松开指节,释放限制器,开始你的咒语。
等等,等等。我说使用稳定的铁锈编译器,这些都是夜间功能。还有,你到底需要这些做什么?";面试官愤怒地问。";我使用的是稳定的铁锈编译器。就像你问的那样,你说给他们看版本号,虽然这更多的是一个技术细节,但是他们还不知道。嗯,好吧,管它呢,继续往前走。
没有libstd,没有核心,只有我,当你放置这条线时,你低声说着,这将使你真正摆脱任何铁锈依赖的束缚。
然后你就会看到面试官脸上那可怜的恐怖表情。好的,让他们深入了解系统的编程真正是什么。好了,IO是函数式程序员试图通过使用纯函数来避免的东西。如果我们想要查看某些东西的输出,我们需要进行某种类型的syscall,因为操作系统是存在的。我们将链接到libc,这样我们至少可以使用printf。我们将在这里使用此行直接链接到OSX libc,但根据操作系统的不同,我们可能希望链接不同的libc实现。
有任何依赖都会让你很痛苦,但你今天不是想要写一个完整的操作系统,那是下周的面试。不幸的是,目前还没有可以使用的库,因此,就像铁匠小心翼翼地将金属环连接在一套链式邮件中一样,您可以链接到受人尊敬的libc。
#[ALLOW(NON_CAMEL_CASE_TYPES)]pub type c_char=i8;#[Allow(Non_CAMEL_CASE_TYPE)]pub type c_int=i32;#[link(name=";system";)]//osx libcextern";C";{pub FN printf(format:*const c_char,.)->;c_int;}。
好的,好的,但是你要谈到真正的问题吗?面试官问,显然是因为你在费心使用C代码而不是println。哦,甜蜜的夏日孩子。一切都建立在科宁汉和里奇的作品之上。我们不能轻易逃脱他们的遗产。
好的,让我们添加一些宏,以便稍后减少一些重复的内容。我们必须把他们放在这里,否则,如果他们在我们召唤他们的地方出现,他们就根本不存在了。你试图让明显失去亲人的面试官相信,你确实理解你正在使用的语言,而且你不会无缘无故地把他们拉来拉去,这样他们就根本不存在了。你试图让明显失去亲人的面试官相信,你确实听懂了你正在使用的语言,而不是无缘无故地把他们拉来拉去。
宏规则!Matches{($Expression:expr,$($Pattern:PAT)|+$(if$Guard:expr)?)=>;{Match$Expression{$($Pattern)|+$(if$Guard)?=>;true,_=>;false}MACRO_RULES!copy_clone_eq_impls{($($t:ty)*)=>;{$(对$t{}实施副本$t{}对$t实施克隆{fn clone(&;self)->;self{*self}}针对$t实施部分Eq{fn eq(&;self,ther:&;$t)->;bool{(*self)==(*Other)})*}}。
他们问道,为什么不从这些东西中推导出来呢?你死死地看着他们的眼睛,向他们解释,我不能通过派生宏为基元实现这些。我必须“成为”编译器本身才能使它们工作。现在让我们继续。我们有一个苹果派要做,首先我们必须发明宇宙。让我们添加一些特性,并导入一些我们将需要的编译器内部功能。
#[lang=";size";]酒吧特征大小{}#[lang=#34;Freeze";]自动特征冻结{}extern";ruust-inherent&34;{FN Offset<;T>;(dst:*const T,Offset:isize)->;*const T;}#[lang=#34;Receiver";]特征接收者{}#[lang=";]特征接收者{}#[lang="。{type output:?size;fn index(&;self,index:idx)->;&;self::output;}针对[T]实施<;T,I&>;Index<;i>;,其中I:SliceIndex<;[T]>;,{type output=I::output;fn index(&;self,index:i)->;&;i::output{index.index。{type output:?size;FN GET(Self,Slice:&;T)->;Option<;&;Self::Output>;;FN get_mut(Self,Slice:&;mut T)->;Option<;&;MUT Self::output>;;UnSafe FN Get_Unecked(Self,Slice:&;T)->;&;Self::OUTPUT;不安全FN GET。MUT T)->;&;mut self::output;fn index(self,Slice:&;T)->;&;self::output;fn index_mut(self,Slice:&;mut T)->;&;mut self::output;}#[lang=#34;copy";]特征复制:克隆{}特征克隆:大小{fn克隆(&;self)->;MUT Self,来源:&;Self){*Self=Soure.clone()}}#[lang=";eq";]特征PartialEq<;RHS:?SIZED=Self>;{fn eq(&;Self,Other:&;RHS)->;bool;FN ne(&;Self,Other:&;RHS)->;bool{!self.eq(Other)(&;Self,Other:&;Self,Other:&;RHS)->;bool{!self.eq(Other)。]特征PartialOrd<;rhs:?size=Self>;:PartialEq<;rhs>;{fn Partial_CMP(&;Self,Other:&;RHS)->;Option<;Ording>;FN lt;(&;Self,Other:&;RHS)->;bool{Matches!(self.part_cmp(Other),Some(Less))}FN。Bool{Matches!(self.part_cmp(Other),Some(Less)|Some(Equity))}fn GT(&;Self,Other:&;RHS)->;bool{Matches!(self.Partial_CMP(Other),Some(Greater))}FN ge(&;Self,Other:&;RHS)->;bool{Matches!(self.Partial_CMP(Other),Some(Greater)|Some(等于。]特征非{type output;fn not(Self)->;self::output;}#[lang=";neg";]特征负{type output;fn neg(Self)->;self::output;}#[lang=";sub";]特征Sub<;rhs=self>;{type output;Fn sub(self,rhs:rhs)->;self:output;
就像任何配得上他们的海盐的好的Rustacean一样,你已经把每一点libstd和libcore都钻进了你的脑海,所以你只把你需要的东西放进去,其他什么都没有。你相信零成本抽象,不,你是零成本抽象。甚至可能只为一个CPU周期或更多的CPU付费也会让你反感。只运行必须运行的内容,不运行其他内容。
等等,这些特征和项目不是来自libcore和libstd吗?什么。这是怎么回事?你的面试官问道,显然很苦恼,因为它需要这么多代码。是的,因为我们使用的是#![no_core],它们根本不存在了。我们只是确切地定义了我们需要从那里得到什么,没有更多的东西。此外,我还尽可能明确地让您看到在任何机器上编程所需的真实成本,去掉语法和预置代码。说到糖有咖啡吗?我喜欢黑色,就像我卖给他们的灵魂一样,以便在这类事情上做得更好。也许这个自嘲的笑话有点过头了,即使这是真的。你只是想缓和一下气氛,但面试官似乎假装什么也没听到。
好的,现在让我们实现所有这些特性!";您可以说,手指在键盘上飞来飞去,永远不会离开插入模式。Esc,h,j,k,l?哈,那些钥匙是给那些没有献身于深渊的人的。
对[T]实施<;T,I&>索引<;I>;其中I:SliceIndex<;[T]>;,{type output=I::output;fn index(&;self,index:i)->;&;i::output{index.index(Self)}}特征切片索引<;T:?size>;{type output:?size;fn get(self,Self::output>;;fn get_mut(self,Slice:&;mut T)->;option<;&;mut self::output>;;unSafe FN get_unecked(Self,Slice:&;T)->;&;self::output;unsafe fn get_uncheck_mut(self,Slice:&;mut)->;&;mut self::output;self::output;fn index_mut(self,Slice:&;mut T)->;&;mut self::output;}#[lang=";copy";]特征复制:克隆{}特征克隆:大小{fn clone(&;self)->;self;fn clone_from(&;mut self,source:&;self){*self=source e.clone()}}#[lang=。rhs:?size=Self>;{fn eq(&;Self,Other:&;RHS)->;bool;FN ne(&;Self,Other:&;RHS)->;bool{!self.eq(Other)}}#[lang=";Partial_Ord&34;]特征PartialOrd<;RHS:?SIZED=Self>;:PartialEq=Self<;:Partial Eq<;RHS)->;option<;订购>;;FN lt(&;self,Other:&;RHS)->;bool{Matches!(self.part_cmp(Other),Some(Less))}FN LE(&;Self,Other:&;RHS)->;
#[lang=";start";]fn start<;T:Terminate+';static>;(main:fn()->;T,_:isize,_:*const*const U8)->;isize{main().report()as isize}fn main(){unsafe{printf(";值为:%d\n\0";as*const U8)->;isize{main().report(){unsafe{printf(";;值为:%d\n\0";as*const。
就是这个。最后一段时间。这种期待简直要了你的命。此类型签名的用途是什么?从什么开始?!生锈没有运行时间!";,你的面试官支支吾吾地说。你转向他们,魔鬼曾经玩过的最伟大的把戏是让C和Rust程序员相信他们的语言没有运行时。";你回到你的计算机上。你叹了口气说,看,我们快做完了。这是我发誓的最后一点。";您开始键入最后的单词,当您最终执行代码时,这将使您拥有O(1)的运行时间和O(1)的空间使用量。到目前为止,你所做的咒语中,确实是最神奇的。
发布常量重复:U64={发布常量列表:&;&39;静态[U64]={不安全{&;*repr{raw:FatPtr{data:&;[1u64,2u64,3u64,7u64,4u64,5u64,6u64,7u64,8u64,9u64,10u64,]as*const u64,len:11,},}.rust}};const。Item!=0usize{Recurse(Item-1,10)}//否则If Compare==0&;&;Item==0//鸽子洞原则表示我们保证能处理这种情况否则If Compare==Item{Recurse(Item,Compare-1)}Else{If List[Compare]==List[Item]{Returse List[Compare];}Else{Recurse(Item,Compare-1)}递归(10,10)}。
等等,等等,这就是天真的解决方案!面试官说,这是O(n^2)Runtime!";,面试官对你重复它们的繁琐感到恼火。不,不,那只是理论上正确的!";你会说,在实践中,const的使用会使编译器将时间和空间保持不变!小心!";你自己动手打开地狱之门,键入异端咒语,只有享有特权的生锈程序员才能用来编译编译器,以免黑社会的滋生摧毁稳定的幻觉。
Interview is📦v0.1.0 Via🦀v1.43.0❯rustc_bootstrap=1 Cargo Run--Release编译氧化-The Interview v0.1.0(/Users/Z̴̧̡̢̨̛A̷̡̡̢̢̡L̶̢̧̢̪̬Ģ̵̡̢̢̧̛Ơ̵̡̡̬͇̬ASM Finish Release[优化]Target(S)在0.17秒内运行`📦/Release/Interview`值为:7Interview is ASM v0.1.0 Via🦀v1.43.0❯RUSTC_BOOTSTRP=1 Cargo Rustc--Release-emit ASM编译访谈v0.1.0。s)在0.19s访谈中是📦v0.1.0通过🦀v1.43.0❯CAT SECTION__TEXT,__text,常规,纯指令.macosx_version_min 10,7.globl_main_main:Push q%RBP movq%rsp,%rbp leaq l_unname_1(%rip),%rdi movl$7,%esi xorl%eax,%eax callq_printf xorl%eax,%eax popq%rbp ret.Section__text,__constl_unname_。值为:%d\n";.subsections_via_symbol target/release/deps/interview-6201aba656776dbc.s为📦v0.1.0,通过🦀v1.43.0❯CAT sInterview|wc-l 20。
看,我告诉过你我只会使用稳定的编译器。你只要相信我就行了!现在看看这段代码的ASM输出。只有20行!17行,如果你去掉空行的话!不需要手写程序集!这都是高级锈码,看看7在里面,它只是被推入一个寄存器并打印出来,所以我在实践中证明了它是恒定的时间和空间!&34;
你的面试官眼睛发白,转过头来说:“我们稍后再联系你。”谢谢你的光临。哦,不,你以前听过这句话。你。
..