编译器作为教师

2021-07-28 00:53:40

在介绍我们的培训时,我们想强调 Rust 非常重视其对开发人员友好性的承诺,并且 Rust 编译器将混淆错误消息视为错误。这一直是 Rust 项目在 1.0 版本之前的明确观点:如果您在 Rust 中遇到令人困惑的编译器错误消息,我认为这是一个错误。请报告(并抄送 @wycats)— Yehuda Katz (@wycats) 2015 年 5 月 18 日在当前正在进行的培训课程中,我们意外地在一次培训中完美地捕捉到了这个过程。在前一天用 match 和 enums 介绍了控制流之后,我们以“填空”练习开始了我们的课程,以帮助我们的参与者进入正确的培训思维空间并练习他们学到的东西。 # [derive ( PartialEq , Debug )] enum FarmAnimal { Worm , Cow , Bull , Chicken { num_eggs : usize }, Dog { name : String }, } fn what_does_the_animal_say (animal : & FarmAnimal ) { /* TODO: 填写匹配下面的语句 */ /* 使此代码编译 */ let noise = match animal { /* Cow and Bull */ => { "moo" .to_string () } /* Chicken */ => { "cluck, cluck! ” .to_string () } /* 狗 */ => { 格式! ( "woof, woof! I am {}!" , name ) } /* 蠕虫——或所有沉默的动物?*/ => { "-- (沉默)" .to_string () } }; /* 奖励任务:给名为 Lassie 的狗 */ /* 一个不同的输出 */ println! ( "{:?} 说:{:?}" , 动物 , 噪音 ); } fn main () { what_does_the_animal_say ( & FarmAnimal :: Dog { name : "Lassie" .to_string () }); what_does_the_animal_say ( & FarmAnimal :: Cow ); what_does_the_animal_say ( & FarmAnimal :: Bull ); what_does_the_animal_say ( & FarmAnimal :: Chicken { num_eggs : 3 } ); what_does_the_animal_say ( & FarmAnimal::Worm ); /* 输出应该是:Dog { name: "Lassie" } 说:“woof,woof!我是 Lassie!”牛说:“moo” 公牛说:“moo” 鸡 { num_eggs: 3 } 说:“咯咯,咯咯!”蠕虫说:“--(沉默)” */ } 在我们的一个参与者看到一条令人困惑的错误消息后,他们分享了他们的屏幕,以便我们可以一起学习和调试。

他们曾尝试将他们所学到的使用通配符模式匹配枚举字段的知识付诸实践,但是 - 就像多个学生一样 - 尝试使用没有任何字段的枚举变体:#[derive(PartialEq, Debug)]enum FarmAnimal { Worm, Cow, Bull, Chicken { num_eggs: usize }, Dog { name: String },}fn what_does_the_animal_say(animal: &FarmAnimal) { let noise = match animal { - /* Cow and Bull */ => "moo" .to_string(), + FarmAnimal::Cow(_) => "moo".to_string(),// ... 这对他们来说很有意义,因为这是我们在前面的例子中教授枚举匹配的主要方式。但是,这种语法选择产生了一条错误消息,对于尚不熟悉有关枚举变体风味的所有术语的人来说,很难解释该消息:错误 [E0532]:预期的元组结构或元组变体,发现单位变体 `FarmAnimal::牛`--> src/main.rs:15:9 |15 | FarmAnimal::Cow(_) => "moo".to_string(), | ^^^^^^^^^^^^^^^ not a tuple struct or tuple varianterror: aborting due to previous error有关此错误的更多信息,请尝试`rustc --explain E0532`。错误:无法编译`playground `要了解更多信息,请使用 --verbose 再次运行该命令。这条错误消息准确地告诉他们出了什么问题,但使用他们还不理解的语言,与许多其他诊断不同,并没有告诉他们该怎么做!与全班一起工作,我们解决了问题和困惑,但为了证明误导性错误消息确实是 rustc 中的错误,我们在培训期间打开了一个关于此的诊断问题。当时,这感觉是向他们展示 Rust 跟踪这些问题并不断改进它们的好方法。我们没想到的是,我们将在培训期间展示诊断报告的完整周期:

在我们报告该问题的一天后,@ABouttefeux 要求实施该问题。在我们报告三天后,新的诊断已经实施并合并,现在我们的培训参与者对我们热身练习的解释存在于测试套件中,具有改进的 UI:错误 [E0532]:预期的元组结构或元组变体, 发现单位变种 `FarmAnimal::Cow` --> $DIR/issue-84700.rs:15:9 | |牛,| --- `FarmAnimal::Cow` 定义在这里... | FarmAnimal::Cow(_) => "moo".to_string(), | ^^^^^^^^^^^^^^^^^^ 帮助:改用以下语法:`FarmAnimal::Cow`有关此错误的更多信息,请尝试`rustc --explain E0532`。因为这是在为期 8 天的会议开始时发生的,所以我们今天要向我们的小组报告他们刚刚为 Rust 编译器做出了贡献。更好的是,在明天的晚上,我们可以重新审视这个例子,向他们展示他们帮助影响的变化。在我们甚至讨论 Lifetimes 和 Strings 之前,所有这一切!实施这些诊断通常是一个挑战,因为您同时需要两件事: 一个对语言足够新的人,会遇到有经验的眼睛的问题会直接跳过 一个知道可以在那里推荐什么的人,以避免问题摆在首位 幸运的是,在进行这些培训时,我们通常拥有完全正确的因素组合来实现这一奇迹。有时,这会导致我们改进我们的培训材料,有时它让我们找到编译器可能会发现的绊脚石。

在我们的培训期间,我们依靠编译器作为另一个助教,因为它经常准确地指出我们的学生需要看到的内容。毫无疑问,对于语言的新学习者来说,在他们需要的时间和地点提供上下文信息是一种宝贵的资源。对于编译器、作为培训师的 Ferrous 以及编译器本身的工作人员来说,新学习者也是一个令人难以置信的资源:他们向我们所有人展示了我们如何更好地教授和支持每个人,使每个人都能更容易地构建令人惊奇的东西。特别感谢@ABouttefeux 为我们的学生清除了这个绊脚石,并帮助使这成为一个了不起的教学时刻。如果您有兴趣为自己或您的开发团队进行培训,请查看我们提供的课程的培训页面,或直接与我们联系以获取更多详细信息!