Go 支持运算符重载吗?

假设有一个学生结构体(面向对象中的类),拥有名字和年龄两个字段。现在想仅根据年龄的大小来判断学生的大小和相等关系。这个需求很简单,一个方法就可以搞定。那是否可以用 = != > < >= <= 这四个运算符来直接对实例进行比较呢? 先看一下 Python 中怎样实现: class Student: def __init__(self, name: str, score: int) : self.name = name self.score = score def __eq__(self, other): # equal if isinstance(other, Student): return self.score == other.score else: raise TypeError(type(other)) def __lt__(self, other): # less than if isinstance(other, Student): return self.score < other.score else: raise TypeError(type(other)) def __gt__(self, other): # greater than if isinstance(other, Student): return self.score > other.score else: raise TypeError(type(other)) def __le__(self, other): # less equal if isinstance(other, Student): return self.score <= other.score else: raise TypeError(type(other)) def __ge__(self, other): # greater equal if isinstance(other, Student): return self.score >= other.score else: raise TypeError(type(other)) if __name__ == '__main__': s1 = Student("Paul", 88) s2 = Student("Tom", 88) print(s1 >= s2) print(s1 <= s2) print(s1 < s2) print(s1 == s2) 借助双下方法,我们可以轻松实现。 ...

June 15, 2022 · 2 min · 扬扬得意

【译】 第六章:搜索

本文翻译自:Hecto, Chapter 6: Search – Philipp Flenker – Engineering Manager ,封面图也来自于此。 我们完成了文本编辑器 — 能打开、编辑和保存文件。接下来的两个功能给它增添了更多的能力。我们会实现一个小小的搜索功能。 为此,我们重用 prompt() 。当用户输入查询请求并按下回车时,我们会遍历文件中的所有行,如果某行包含查询字符串,会移动光标到匹配的位置。为了达到这个目标,我们需要一个在单行搜索并返回匹配位置的方法。现在让我们开始实现。 到 GitHub 查看这一步。 // 译者注:editor.rs 中 135-142 代码如下 Key::Ctrl('f') => { if let Some(query) = self.prompt("Search: ").unwrap_or(None) { if let Some(position) = self.document.find(&query[..]) { self.cursor_position = position; } else { self.status_message = StatusMessage::from(format!("Not found: {}.", query)); } } } 我们先从 Raw 开始,过一遍这次改动。我们添加了一个返回 Option 的函数。Option 要么包含匹配单词的 x 坐标,要么是 None。用 String 中的 find 方法检错匹配单词的字节索引。记住这可能跟字形索引不太一样!为了把字节索引转换为字形索引,我们使用了一个稍微有点绕的循环。让我们解释一下。grapheme_indices() 为字符串中每一个字形返回一对 (byte_index, grapheme) 的迭代器。enumerate() 枚举这个迭代器,所以,它会给我们迭代器元素的索引。我们利用这一特点,遍历迭代器,直到我们到达与我们匹配单词有相同索引的字形,并返回相应的字形索引。 ...

May 15, 2022 · 3 min · 扬扬得意

【译】 第五章:文本编辑器

本文翻译自:Hecto, Chapter 5: A text editor – Philipp Flenker – Engineering Manager,封面图也来源自此。 现在 hecto 能读取文件了,让我们看看能不能让它也能编辑文件。 插入常规字符 首先,让我们写一个函数,在给定的位置将字符插入到 Document 中。我们先在指定位置向字符串添加一个字符。 到 GitHub 查看这一步。 // 译者注:52-53 行代码如下 let mut result: String = self.string[..].graphemes(true).take(at).collect(); let mut remainder: String = self.string[..].grephemes(true).skip(at).collect(); 先看看 Row 中的改动。我们处理了两种情况:如果插入位置碰巧在字符串末尾,则插入该字符。该情况发生于用户在行尾不断打字的情景下。另外一种情况,通过逐个遍历字符来重建字符串。我们使用了迭代器的 take 和 skip 函数来创建新的迭代器。一个迭代器从 0 到 at (包含 at ),另一个迭代器从at 后到末尾。我们使用 collect 来组合这两个迭代器为字符串。collect 非常有用并且能转换为不同的集合。因为 collect 能创建多种集合,所以我们需要声明 result 和 remainder 的类型,否则 Rust 无法知道创建的集合的类型。现在也为 Row 派生了 default。我们将在 Document 中使用它。 与 Row 中做法类似,我们要处理用户试图在 Document 底部插入字符的情况。对于该情况,创建一个新行即可。 ...

May 7, 2022 · 4 min · 扬扬得意

【译】 第四章:文本阅读器

本文翻译自:Hecto, Chapter 4: A text viewer – Philipp Flenker – Engineering Manager,封面图也来源自此。 让我们在这章中看看能不能把 hecto 变成一个文本阅读器。 行阅读器 我们还需要一些数据结构:Document 表示用户现在正在编辑的文档,和 Row 表示该文档中相应的行。 到 GitHub 看这一步。 在这次改动中,我们在代码中引入了两个新概念:第一,使用了一个叫作 Vector 的数据结构,它会存储行。 Vector 是一个动态结构 — 当我们增加或者删除元素时,它可以在运行时扩充和缩小。语法 Vec<Row> 表示 Vector 会存储类型为 Row 的元素。另一个新概念是这行: #[derive(Default)] 它表示 Rust 编译器应该派生 default 的实现。default 返回每个字段都被初始化为缺省值的结构体,这是编译器能为我们做的事。有了派生,我们不必自己实现 default。 让我们看看用派生是否还能简化现在的代码。 到 GitHub 看这一步。 通过为 Position 派生 default ,我们移除了重复初始化光标位置为 0,0 的代码。如果将来,可能我们决定以另外一种不同的方式初始化 Position ,那么就自己实现 default,而不需要修改其他的代码。 我们不能为其它非常复杂的结构体派生 default。因为 Rust 不能估计结构体所有字段的默认值。 现在,让我们用一些文本填充 Document 结构体。我们还不必考虑从文件中读取内容的问题。相反,我们先在其中硬编码一个 “Hello, World” 字符串。 ...

April 30, 2022 · 4 min · 扬扬得意

【译】 第三章:原始输入输出

本文翻译自:Hecto, Chapter 3: Raw input and output – Philipp Flenker – Engineering Manager,封面图也来源自此。 在这一章中,我们会解决从终端读取和向终端写入的问题。但是,首先,我们需要让代码更加地道。注意!本章的开头会包含大量的无聊文字,如果你不感兴趣,可以直接跳过。 写地道的代码 每当你和 Rust 这样的新语言打交道时,你会经常听到地道代码的说法。显然,让代码解决问题是不够的,它还应该是地道的。先让我们讨论一下这样为什么是有意义的。因为地道这个术语来自语言学,我们就举一个语言学的例子:如果我告诉你,有了本教程,你可以 “kill two flies with one swat”(直译为:一拍打死两个苍蝇,即一石二鸟、一箭双雕),因为你可以在学习 Rust 的同时,编写自己的编辑器。你能明白的我的意思吗? 如果你是个德国人,你大概不会有疑惑,因为 “Killing to flies with one swat” 是一句近似直译的德国谚语。如果你是俄罗斯人,“killing two rabbits with one shot”(直译为:一枪打死两只兔子) 对你来说会更好理解。但是如果你不了解德语和俄语,就不得尝试不从上下文中猜测(extract)句子的意思。因为地道的英文表达方式是 “To kill birds with one stone”(译者注:即中文成语一石二鸟)。重点是使用正确的英语俗语可以确保每个人无需思考便可理解意思。如果你说的语言不地道,你就会迫使人们思考你所使用的措辞,而不是你提出的观点。(译者注:作者说的地道指的是更加符合语言惯例和语法规则。比如那句出名的 Chinglish — Good Good Study,Day Day Up 对于中文母语者来说没有理解压力,但是英语母语者就会丈二和尚摸不着头脑。) 写地道代码也是类似的。对其他人来说,它更容易维护,因为它坚持某些规则和惯例,这也是编程语言设计者所考虑的。 你的代码通常只有在不能运行, 或者是功能缺失,有人想扩展功能, 或者是有 Bug 时才会被别人审核(Review)。让代码更容易被别人阅读和理解通常来说是一个好主意。 我们之前看到过,Rust 编译器能够给你一些关于地道代码的建议。 比如,我们在一个不使用的变量前加上了下划线。我的建议是不要忽略编译器的警告,你的最终代码应该总是在没有警告的情况下编译。 不过,在本教程中,我们有时会提前添加功能,这将导致 Rust 警告代码不可用(unreachable)。这通常在一两步之后就会被修复。 让我们通过使代码更地道开始本章吧。 读取按键而不是字节 在前一步中,我们直接操作字节,这是有趣且有价值的。然而,在某个时间段,你应该问下自己,正在实现的功能能否被一个库函数取代。在有些情况下,别人可能早已解决了你的问题,并且可能效果更好。对于我来说,用位操作处理是一个巨大的警示灯,它告诉我,我可能在细节中陷得太深。 ...

April 23, 2022 · 6 min · 扬扬得意