Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

「第三章」3.4.2 泛型约束 数学角度描述 trait 中的概念混淆与逻辑错误 #99

Open
eZioPan opened this issue Jan 22, 2019 · 24 comments
Labels
内容描述错误 内容描述有违事实 已修订 已经修订并提交给出版社 第三章 第三章 精选
Milestone

Comments

@eZioPan
Copy link

eZioPan commented Jan 22, 2019

页码与行数

  • 第 70 页
  • 理解 trait 限定

文本或排版错误

文中说

trait 也是一种类型,是一种方法集合,或者说是一种行为的集合

然后举了 PaginatePagePerpage 三者之间的关系,并推导出

这样的联系。

整个段落混淆了 泛型标记实类型,同时也引发了逻辑错误


对于

trait Paginate: Page + Perpage

根据大前提 trait 是 方法集合,我们可以认为

同时,根据书中 第 68 页

代码清单 3-32:使用 trait 继承扩展功能

这里指出了 Paginate trait 中定义的 method 默认包含 Perpage traitPage trait 中定义的 method,也就是说

对于

都有

可推导出

与书中的表述是不相符的。


因此

trait Paginate: Page + Perpage

中的 加号 表示的是 并集


同理

impl<T: A + B> C for T { . . . }
fn<T: A + B> foo(bar: T) { . . . }

若把 TAB 都看成是 以某些方法为元素的集合

加号 依旧表示 并集

A + B 表示的是 trait Atrait B 中所有方法的总集合

对于 泛型标记 T 来说,冒号 表示 T 可以使用冒号后的 trait(s) 所具有的所有方法

对于 某个实类型 CT 来说,冒号 才是对它的限制:要求 CT 至少实现冒号后 trait(s) 定义的所有的方法才可以被当作泛型标记 T 来使用


若一个 实类型 CT 的确满足了泛型标记 T 的要求,

还将 实类型 CT,泛型标记 T,trait A,trait B 都看作 以某些方法为元素的集合 的话,有下述关系

这里与本页中

“为所有 实现 Trait C”

也不相符


Rust 编程的哲学是组合优于继承 这段中

所以 Rust 中的类型可以看作语言允许的最小集合,不能再包含其他子集。而 trait 限定可以对这些类型集合进行组合,也就是求交集

这两句话在数学逻辑上也是冲突的:交集 产生的就是原集合的 子集,与 不能再包含其他子集 冲突

对于 实类型 来说, trait bound 是一种具有 排除性质 的限定, trait bound 不关注 实类型 到底实现多少方法,只关注 实类型 没有实现的方法,一旦 实类型 没有实现 trait bound 中的全部方法,就标记该 实类型 不符合 trait bound

对于 泛型标记 来说, trait bound 是具有 累加性质 的限定,trait bound 不关注 泛型标记 实际使用了多少方法,只关注 泛型标记 已经使用的方法,一旦 泛型标记 使用了不存在于 trait bound 中的方法,就提示错误。

@ZhangHanDong ZhangHanDong added 第三章 第三章 内容描述错误 内容描述有违事实 待确认 待确认的问题 labels Jan 22, 2019
@ZhangHanDong
Copy link
Owner

@eZioPan 感谢这么详细的反馈。我找时间确认下再讨论。

@mzji
Copy link

mzji commented Jan 22, 2019

顺带纠正一处问题: trait 不是类型, trait object 才是。

@ZhangHanDong
Copy link
Owner

ZhangHanDong commented Jan 23, 2019

@mzji trait是一个Unsize类型。Rust类型系统下,一切皆类型

@mzji
Copy link

mzji commented Jan 23, 2019

trait 不是类型。证据:你不能创建 trait 的实例,但是你可以创建 trait object 。

@mzji
Copy link

mzji commented Jan 23, 2019

更严谨的说法是,对于满足 object safety 的 trait 来说,每一个这样的 trait 都有一个对应的类型 dyn trait ,这个类型的实例就是这个 trait 所对应的 trait object 。

@ZhangHanDong
Copy link
Owner

ZhangHanDong commented Jan 23, 2019

@eZioPan 刚才仔细看了你的内容,你说的没问题。其实我在写的时候,也是想表达类似的意思,但是不知道为啥把并集搞错成了交集。 可能我脑子里想的是 T 和 T: Trait交集是Trait。

感谢你的澄清。

@ZhangHanDong ZhangHanDong removed the 待确认 待确认的问题 label Jan 23, 2019
@ZhangHanDong ZhangHanDong added this to the 第三次印刷 milestone Jan 23, 2019
@lagudomeze
Copy link

如果把trait 认为是类型的集合
Type:TraitA + TraitB
是不是可以看作 Type 属于 集合(TraitA) 和 集合(TraitB)的交集?

@kvinwang
Copy link

对于 实类型 来说, trait bound 是一种具有 排除性质 的限定, trait bound 不关注 实类型 到底实现多少方法,只关注 实类型 没有实现的方法,一旦 实类型 没有实现 trait bound 中的全部方法,就标记该 实类型 不符合 trait bound

检查bound的时候,只需要检查有没有impl这个trait就好了,不用逐个检查方法有没有实现。impl的时候才会检查有没有实现全。

@eZioPan
Copy link
Author

eZioPan commented Jan 25, 2019

@ZhangHanDong @angelrain1 我想两位说的应该是近似的意思了。本质上我们都是对同一个内容的不同描述方法,都没错。我的描述中将加法解释为并集比较符合数学上的直觉,而将冒号解释为限制是来源于冒号在 Rust 通常用法下的衍生:对变量的类型的限制。

这里我也建议张老师在这段体现一下 实类型泛型标记 之间的差别,直接使用 TT:Trait(s) 可能太容易让人混淆了。就像在描述函数的声明和调用的时候要区分 形式参数parameter) 和 实际参数argument) 一样,区分出来就更明确了。

@ZhangHanDong
Copy link
Owner

@eZioPan 嗯,正在考虑如何修正内容。后续再讨论。

@yim7
Copy link

yim7 commented Jan 25, 2019

张老师可能是想讲解的通俗易懂,只是描述不够准确
"T 属于 A 与 B 的交集",这里的 A 、B 如果解释成是 impl A 的类型集合以及 impl B 的类型集合就没问题了。但是在之前 A B 都是值的 Trait,所以这句话模糊且多余,Trait bound 只关心 T 是否 impl A + B,并不检查 T 是否在 impl A 或者 impl B的集合中。只要解释清楚 Trait bound 是如何约束泛型、Trait,过多的解释可能并不能帮助读者理解问题~
刚好又想到一点,说 supertrait 继承也不准确,trait A: B, impl A 必须 先impl B,两个 trait 实际是独立的,impl A 不会继承 B 的方法
感觉张老师喜欢用类比解释问题

@ZhangHanDong
Copy link
Owner

@yim7 这个地方确实描述的不够精确。

其实我书里并没有说trait继承,是A会继承B的方法。trait用作限定,trait继承,可以理解为继承这种「行为的限定」。不过这部分内容,后面也会出一个修正,后续再继续讨论。

类比解释,只是写作的一种方式罢了,这个地方我感觉用数学集合解释比较有趣。

@ZhangHanDong
Copy link
Owner

ZhangHanDong commented Feb 9, 2019

@eZioPan @yim7 @mzji

总结一下:

  • trait可以看作是一种类型。毕竟trait bound也是参与类型检查的。
  • impl<T: A + B> C for T,解释为,“为所有T⊂(impl A∩ impl B)实现Trait C”,也就是说,“为所有同时实现了A和B的类型T实现C”。这样不会引起歧义了。

对于trait方法来说,确实是并集。但我书里的内容,这不是重点。重点是被trait限定的类型。这些类型要求,即实现A,又实现B,那么就是交集了。

@ZhangHanDong ZhangHanDong added the 已修订 已经修订并提交给出版社 label Feb 9, 2019
@LEXUGE
Copy link

LEXUGE commented May 29, 2019

我来总结一下:
首先,这里问题出现的关键在于各位对于 A, B, T, C 这些集合的定义。

  • 如果定义 A, B, C
    image
    T 即为其所有 Type 的话,那么 A, B, T, C 满足的关系应为
    image
    image

  • 如果定义 A, B, C
    image
    T 即为其类型所有实现的 methods 的话,那么 A, B, T, C 满足的关系应为
    image
    image

我认为张老师可以再对描述润色一下,使其更严谨。
但需要指出的是,无论那种理解,第三章插图3-5中的画法都是错误的

@ZhangHanDong
Copy link
Owner

@LEXUGE 感谢反馈,晚点再回复。

@LEXUGE
Copy link

LEXUGE commented May 31, 2019

我写了一篇博客(英文),应该更加完整一些

@ZhangHanDong
Copy link
Owner

@LEXUGE

@LEXUGE
Copy link

LEXUGE commented May 31, 2019

@LEXUGE

其实你在书中 impl<T: A + B> C for T 这句语句是很难用维恩图或者集合来描述的,因为C 和 T都很具有任意性。这样就给描述造成困难。
我觉得我在博客里总结的两条inference应该还是能算是简单推导出来的,如果要描述你的那句语句的话可能就要各种分类讨论(比如T有没有实现A/B/C的sub/supertrait),以我的能力感觉有困难。

@ZhangHanDong
Copy link
Owner

@LEXUGE 我在书里的图,只是想给读者一种启迪的作用,方便大家理解trait。

@LEXUGE
Copy link

LEXUGE commented Jun 1, 2019

@LEXUGE 我在书里的图,只是想给读者一种启迪的作用,方便大家理解trait。

原来是这样啊...那我看书时有点较真了

@ZhangHanDong
Copy link
Owner

@LEXUGE 没事,这样挺好,可以帮助我提升准确度。

@gm3000
Copy link

gm3000 commented Aug 22, 2019

能否把把电子版也修改一下呢,也是花了钱买的

@ZhangHanDong
Copy link
Owner

@gm3000 我知道你是花了钱买的,但是电子版也不是我能直接控制的。 出版社需要修订,修订完还得交给售卖平台上架,这里面也有很多工序。我只能催促出版社,出版社再催促平台,如果我能直接控制,我早修改了。

@colinger
Copy link

在看到这段时,还以为我一直把这个关系理解错了,一开始以为是Rust的特色。又去验证了一下,又查了一下,看到此页,原来是作者笔误。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
内容描述错误 内容描述有违事实 已修订 已经修订并提交给出版社 第三章 第三章 精选
Projects
None yet
Development

No branches or pull requests

9 participants