我最喜欢的铁锈函数签名

2020-09-17 23:10:19

1266布兰登·史密斯(Brandon Smith)最近非常着迷于编写解析器,而Rust被证明是实现这一目标的完美语言。在我的冒险过程中,我想到了以下几点:

对于那些不熟悉解析的人来说,标记化是该过程的第一步。它接受原始代码字符串,如下所示:

这一阶段并不是非常复杂,但它简化了下一步的心理模型:构建抽象语法树。它删除了等式中的空格,将字符串和数字等段捆绑在一起,通常只是使下一遍中的代码更干净。

缺点是,如果您将其作为单独的传递执行,解析器现在必须迭代所有源代码两次。这可能不是世界末日:代码化并不是最昂贵的操作。但这并不理想,因此一些解析器将两个遍合并为一个遍,以牺牲可读性为代价节省了周期。

在Rust中,&;str是一个";字符串片";。它实际上是一个字符指针和一个长度。切片的内容被保证在有效的活动存储器中。&;';字符串是具有生存期的字符串片。确切地说,是一生。此生存期描述了保证引用(和片的全部内容)在有效的活动内存中的有限时间跨度。稍后会详细介绍这一点。

迭代器<;item=&;&39;字符串是对字符串类型的元素的迭代器。然而,这是一种特质,而不是一种具体的类型。当您重新定义函数之类的东西时,Rust需要具有固定大小的具体类型,但幸运的是,我们可以说Iml Iterator<;Item=&;&39;a str>;,它告诉Rust,填充一些实现Iterator<;Item=&;a str&>的类型,以便在编译时推断。这非常有用,因为在Rust中,Iterator有很多不同的具体类型;应用诸如map()或filter()之类的应用程序将返回一个全新的具体类型。因此,通过这种方式,我们不必担心在处理逻辑时使函数签名保持最新。

好的,我们有一个函数,它接受对字符串片段的引用,并返回字符串片段上的迭代器。为什么有那么特别?原因有两个。

还记得我说过,您传统上必须在执行单独的标记化过程和在所有逻辑交错的情况下执行单个过程之间进行选择吗?使用迭代器,您可以两全其美。

当这个函数完成时,它还没有遍历字符串。它没有在内存中分配任何类型的集合。它返回一个结构,该结构已准备好在输入字符串片上迭代并生成一系列新的片。当稍后将此值映射()到其他内容中时,或者应用filter(),或者应用任何其他迭代器转换时,该过程的各个阶段将交错,并且循环有效地合并为单个循环。通过这样做,我们能够获得标记化传递的干净抽象,而不需要第二个循环的运行时开销!

但是其他语言有迭代器。生锈可能是额外的强大和符合人体工程学,但他们并不是一个完全独特的功能。下一部分对铁锈来说是非常独特的。

函数的作用是:不为令牌集合分配任何新内存。那真是太棒了。但可能不太明显的是,它也没有为令牌本身分配任何内存!表示令牌的每个字符串片都是指向原始字符串部分的直接指针。

当然,您可以在C/C++中做到这一点,但这有一个危险:如果在释放原始代码字符串之后访问这些令牌,您将会出现内存错误。

例如:假设您打开一个文件并从中加载源代码,然后将结果存储在一个局部变量中。然后将其标记化(),并将标记发送到原始字符串所在的函数之外的其他位置。瞧,你有一个释放后使用的错误。

防止这种情况的一种方法是将每个字符串段复制到堆上分配的新字符串中,这允许您在原始字符串消失后安全地传递它。但这是有代价的:创建、复制并最终处理每个新字符串都需要时间(和内存)。下面的代码还必须意识到它负责释放这些字符串,否则它们会泄漏。

生锈完全可以防止上述情况的发生。不过,要实现这一点,从其他地方进入函数的字符串必须假定是静态的,或者在程序执行的整个过程中都是活动的(&A;STR)。这是分配给的状态,例如,您已手动输入到您的Rust代码中的字符串文字。在函数的上下文中,Ruust不知道该引用将在多长时间内有效,因此它肯定是悲观的。

但。那个小东西上写着:这些东西都活着同样的时间跨度。我们可以断言,原始源代码字符串至少与引用它的标记一样长。通过这样做,Rust可以推断得到的令牌引用在给定点是否有效,因此不必假定它们是静态的!我们可以随心所欲地处理这些令牌,编译器将保证它们始终指向有效的内容,即使源代码是在运行时动态加载的(从文件或其他方式)。如果我们稍后通过编译器错误发现它们确实需要比源字符串更长的生存期,那么我们可以在那时复制它们(";取得所有权";)。如果编译器不强制我们这样做,我们知道我们是安全的,我们知道我们可以继续使用最有效的方法,无所畏惧。

我们已经有效地编写了尽可能乐观的函数(就内存安全而言),没有任何缺点,因为Rust编译器会告诉我们是否在误用它,然后迫使我们降到需要额外容纳的任何级别。

我已经使用(并且喜爱)铁锈大约一年半了。有很多值得喜爱的东西,但当我让这个函数工作时,我立即将其视为真正使语言与众不同的一个缩影。这是您不能同时做到a)安全和b)在任何其他语言中有效地做到这一点的原因。这就是铁锈的力量。