附录A
巧克力糕饼食谱
巧克力糕饼食谱
你需要如下原料:
100g黄油
185g 70%黑巧克力
2枚鸡蛋
半茶匙香草香精
185g精白砂糖
50g面粉
35g可可粉
半茶匙盐
70g巧克力屑
制作方法
(1)将烤箱预热到160℃(320℉)。
(2)在15cm×15cm的小烤盘上涂上油并铺上烘焙纸。
(3)将黄油和黑巧克力放在碗里,在装有热水的平底锅上融化。一旦融化,从热源上移开以使其冷却。
(4)在一个碗里打入鸡蛋,放进砂糖和香草香精并搅匀。
(5)在蛋液中加入融化的黄油和黑巧克力并搅匀。
(6)在另一个碗里混合面粉、可可粉和盐,然后筛入鸡蛋、砂糖、黄油和巧克力,充分搅拌使其完全混合。
(7)加入巧克力屑并搅匀,使其混合。
(8)将上述混合物放入烤盘并烘焙20min。
冷却数小时。
附录B
空值安全与可选类型
B.1
使用空值安全
如果我们使用的语言支持空值安全(且我们已按要求启用这一特性),就会有一种注释机制,表示各种类型可取空值。这往往包括表示可为空值的?字符。代码一般像下面这样。
Element? getFifthElement(List<Element> elements) { ←--- Element?中的“?”表示返回类型可以为空值
if (elements.size() < 5) { return null; } return elements[4];}
如果使用这段代码的工程师忘记处理getFifthElement()返回空值的情况,他们的代码将不能编译,如以下代码所示。
void displayElement(Element element) { ... } ←--- 这个函数的参数不可为空(因为类型是Element而非Element?)
void displayFifthElement(List<Element> elements) { Element? fifthElement = getFifthElement(elements); ←--- fifthElement变量可为空,因为它的类型是Element? displayElement(fifthElement); ←--- 这一行将出现编译器错误,因为函数期待一个不可为空的参数,但这里却以可为空的值调用}
为了编译这段代码,工程师必须检查getFifthElement()返回值是否为空,然后才能用它调用参数不可为空的函数。编译器能够推导出哪些代码路径只在该值非空时才能抵达,从而确定该值的使用是否安全。
void displayFifthElement(List<Element> elements) {
Element? fifthElement = getFifthElement(elements); if (fifthElement == null) { displayMessage("Fifth element doesn't exist");
return; ←--- 这条if语句意味着该函数将在fifthElement为空时提前返回 } displayElement(fifthElement); ←--- 编译器可推导出这一行只在fifthElement不为空时可达}
注意:编译器警告与编译器错误的对比
在C#中,以不安全的方式使用可为空的值只会造成编译器警告,而不是编译器错误。如果你使用C#并启用空值安全,那么配置你的项目,将这些警告升级为错误以确保它们不会被忽视,可能是明智的做法。
可以看到,有了空值安全机制,我们可以使用空值,并且编译器将跟踪一个值何时在逻辑上可为空、何时不可为空,并确保不会以不安全的方式使用空值。这样,我们就能从空值的实用性上得益,又不会遭遇空指针异常(以及类似问题)的危险。
具有空值安全机制的语言往往提供简洁的语法,以检查某个值是否为空,并只在值不为空时访问其上的成员函数或属性。这可以消除许多重复代码,但本书的伪代码惯例将坚持更详尽的空值检查形式,使其与更广泛的不提供这类语法的语言类似。