这是 RFC“澄清和简化路径和可见性”(rust-lang/rfcs#2126)的跟踪问题。
脚步:
foo.rs
或foo/mod.rs
支持子模块,如foo/bar.rs
#45385crate
作为可见性修饰符 #45388crate
开始绝对路径https://github.com/rust-lang/rust/issues/45477pub
项目添加 lintcrate
开始绝对路径时被阻止。 除非我们使用该扩展名,否则这些项目都不会生效:crate
开头的绝对路径添加 lint (https://github.com/rust-lang/rust/issues/48722)extern crate
未解决的问题:
我们应该如何处理迁移? 通过后备,如建议,或通过时代? 最好通过更多的经验来做出这个决定,例如在我们手头有一个rustfix
工具之后。
绝对路径的最终语法; 在我们可以实际尝试各种选项的情况下,这里还有更多的自行车棚工作要做。 特别是,同时拥有crate::
和extern::
路径有一些真正的优势,但理想情况下我们可以用更简洁的方式来实现。
::crate::foo
。 但是,我们也将struct Foo(crate ::foo)
解析为非法路径,而不是将crate
视为可见性修饰符。 @petrochenkov描述了此评论中的一些推理。该 RFC 有4 个不同的功能,但我们仍然只有一个跟踪问题。 我们能不能推不在一起不同的功能,这样的吗?
@retep998正如 RFC 讨论中所解释的那样,这些功能通过全局设计考虑因素连接在一起。 例如,提供用于重命名 crate 的外部机制的部分动机是extern crate
的最终弃用。 我们可以并且将分别对各个方面进行门控(并且可能会有一些重叠的门来尝试不同的语法),但是对于整体设计和稳定性的讨论,重要的是要记住全局一致性。
拥有一个外部机制来重命名板条箱是多年来一直希望和需要的东西(https://github.com/rust-lang/cargo/issues/1311)并且可以单独存在就好了,但它正在被使用只不过是支持杀死extern crate
的棋子。
过去,我们在为密切相关的功能设置单独的 RFC 时没有遇到任何问题(想到了repr(align(N))
和repr(packed(N))
的 RFC),但现在我们声称更改了foo/mod.rs
到foo.rs
与extern::
和crate::
密切相关,以至于它们必须在同一个 RFC 中并使用相同的跟踪问题?
只是为了确保这一点仍然存在,因为这是语法未解决问题的一个相对微妙的方面:使用crate
作为可见性修饰符以及路径前缀会在crate ::absolute::path
和crate::relative::path
。 使用上下文关键字会引入相同的歧义,并且没有其他保留关键字作为可见性修饰符真正有意义。
因此,我想(至少)尝试忽略crate
可见性修饰符并坚持使用现有的pub(crate)
。
我不介意将foo.rs
/ foo/mod.rs
点拆分为单独的跟踪问题,因为它似乎确实与路径和可见性修饰符的更改无关。
至于外部板条箱重命名......已经有一个单独的问题? 这对于路径更改非常重要,所以我认为作为其中的一部分也很好。
尽管几周前有很多关于选择crate
作为可见性修饰符(不是路径前缀)的讨论,但我很失望地看到,尽管这种关键字选择被列为“未解决的问题” RFC,现在显然已经被遗忘了。 我自己和我注意到的其他几个人发现这个选择令人困惑,因为它不是形容词/修饰符,而且也可能是模棱两可的: crate
表示 crate 公共 API 的一部分? 不! 这意味着板条箱的local
或internal
或pub
(lished)(因此我更喜欢后者的关键字)。 所以我不要求立即改变,但至少承认它是这个跟踪问题中一个未解决的问题,以便在稳定时不会忘记它。
到目前为止,这个模块的重新设计已经取得了进展,这很棒,但与此同时,重要的是我们不要为了“实施期”而犯错,并最终在没有咨询大多数 Rust 用户的情况下做出决定。 而且,不幸的是,我认为参与 Github RFC 讨论的人不能代表整个用户群,因为信息/评论/意见的泛滥可能会令人沮丧。 因此,这也需要以某种方式处理。
目前尚不清楚实施最终如何......
@rpjohnst @retep998我已经打开了一个新的 RFC来讨论foo.rs + foo/
以及对该 RFC 的一些改进建议。
编辑:我建议我们打开另一个 RFC 来讨论crate
作为可见性修饰符。 就我个人而言,我希望看到相反的情况:所有外部发布的符号都需要添加并需要pub(extern)
。 这将使裸pub
在下一个纪元中等同于pub(crate)
。
@rpjohnst
在 crate ::absolute::path 和 crate::relative::path 之间引入了解析歧义
无论如何, crate ::relative::path
不是无效代码吗? 解析时不能拒绝吗?
@est31不,这需要在解析过程中进行名称解析,这绝对不是我们想要做的。 这是解析 C 和 C++ 中比较烦人的部分之一,它们在a * b
是乘法或声明,以及在a b(c, d);
是变量声明或函数原型周围有类似的歧义。
如果我们开始允许具有相同名称的依赖项和顶级模块,即使将名称解析与解析纠缠在一起也无济于事 - crate :: some :: item
可能是crate
-visible item
来自依赖项some
,或来自顶级模块some
的私有item
some
。
为了正确理解这一点,我们可以任意地以一种或另一种方式解决歧义,并要求括号来编写另一种情况(可能是crate
-visibility 绝对路径情况,这似乎是最罕见的),但这仍然是一个如果我们坚持使用pub(crate)
,我们就不需要foot-gun,它已经解决了句法歧义。
使用 crate 作为可见性修饰符以及路径前缀会在
crate ::absolute::path
和crate::relative::path
之间引入解析歧义。
这是一个小问题,IMO,因为元组结构字段和“内联”绝对路径的可见性都很罕见。
路径当前总是被贪婪地解析,因此crate :: x :: y
表示crate::x::y
是有意义的。
如果需要相反的含义,则可以使用pub(crate) ::x::y
或crate (::x::y)
。
@rpjohnst @petrochenkov你能分享一个代码示例,其中pub ::relative::path
是有效代码吗? 我不明白整个模棱两可的事情,因为我认为这两种情况之一是无效的。
编辑:当您匹配可见性限定符 + 路径时,唯一可能相关的地方是在宏内部。 但这是一个非常小的破损,因此 IMO 可以接受。
@est31您似乎有一个错误的想法-这与相对路径无关,它们从来都不是问题。 这是关于在您知道任何名称所指的内容之前构建 AST。 这是一个完整的示例:
struct S(crate :: x :: y);
鉴于您还不允许查找这些名称中的任何一个,您如何将该字符串转换为 AST? 有两种可能的答案。 一个在当前板条箱的模块x
中定义了一个类型y
的私有字段。 另一个在依赖项x
的顶层定义了一个不同类型的crate
-visible 字段y
x
。 不需要宏。
@rpjohnst我看到感谢您的澄清。 它确实是一个歧义。
@rpjohnst
一个简单的解决方案是将其定义为明确解析为 crate 可见性修饰符。 如果要将其解析为具有给定类型的私有成员的元组结构,请执行以下操作:
struct S(:: crate :: x :: y);
(注意::
前缀表示根“命名空间”)
这与子模块中需要引用其他根命名空间的方式一致(例如::std::x::y
)。
我认为,只是消除crate
-as-a-visibility 的歧义会有些令人惊讶。 但是,稍微“规范化”该解决方法并强制crate::
始终与前导::
(当然在use
之外)可能是一个好主意。 正如您所指出的,这增加了与::std::x::y
类似路径的对称性,并为真正的相对路径保留了无前缀形式( self::
/ super::
/ something_in_scope::
)。
我们应该这样做吗? 在非use
路径中允许crate::x::y
使crate
有点神奇,同时强制::crate::x::y
范围限定为与依赖项相同的级别,这就是我们所做的无论如何都试图暗示。
@rpjohnst
强制
crate::
始终与前导::
使用(当然在使用之外)
这可能是合理的,至少在开始时是这样(没有什么可以阻止以后放松这一点)。
我不喜欢use extern::bar::foo
或use crate::bar::foo
语法。 似乎很吵。 我更喜欢加点糖。 我为此建议extern bar::foo
。
再添加一个隐式规则怎么样? 自动将extern crate导入根命名空间,做一个更重合的路径表达式。(我英语不好,请从下面的例子中学习我的观点)
例如
源文件
|--lib.rs
|--foo.rs
|--foo
|----|--bar.rs
你在 Cargo.toml 中配置了一个依赖项,比如
[dependencies]
serde = "3.0.0"
我们将 mod bar
到 mod foo
,并将 mod foo
到 lib.rs 中,
我们在lib.rs中定义一个函数finlib
在foo.rs中定义一个函数finfoo
在bar.rs中定义一个函数finbar
将 extern crate 的作用域作为 crate 中的顶级模块,然后我们可以在任何地方编写这样的代码。
对于完全/限定路径
::serde::Deserialize
::serde::x::y
::finlib // not ::crate::finlib
::foo::finfoo // not ::crate::foo::finfoo
::foo::bar::finbar // not ::crate::foo::bar::finbar
相对路径这样写
serde::Deserialize // no need to write `use serde`
serde::x::y // no need to write `use serde`
finlib
foo::finfoo
bar::finbar
我们首先在当前 mod 范围内查找 serdefinlibfoo,如果没有在 supper mod 中查找,直到根命名空间。 如果有名字冲突,我们写全路径代替。
我们也可以在 foo.rs 中使用self::bar::finbar
来避免名称查找。
我无法找到讨论此问题的较早线程,但编译器曾经以这种方式工作,并导致名称解析出现重大问题。 IIRC @pcwalton或@arielb1可能知道更多。
解决这种歧义的最简单方法不是为 crate-local 可见性修饰符使用不同的关键字(即: pub(crate)
替换)。 例如, local
,正如之前在之前的 RFC 讨论中多次建议的那样。 然后struct S(local :: x :: y)
与struct S(crate :: x :: y)
。
这只是在<visibility> <absolute path>
和<relative path starting with the new keyword>
之间引入了另一个歧义,因为 new 关键字必须是上下文。
@rpjohnst啊该死的......但这不是时代旨在解决的问题吗? 例如:在当前时代,我们只使用pub(crate)
,然后在下一个时代,引入一个更“符合人体工程学”的新的非上下文关键字。
@neon64是的,但 RFC 声称它不需要新纪元。 这种说法似乎不成立。
它保持得很好 - 目前没有使用crate
可见性或crate::
路径的代码,因此只有新代码会受到影响。 只要我们选择一个解决方案并坚持下去,就不会有兼容性问题。
我发生了一件事情,如果之前在其中一次讨论中被提出过,我深表歉意(我不记得在最后一对中见过它):
在最新的提案中,我们用crate::
来指代“在这个板条箱中”和self::
来指代“在这个模块中”。 这有点不一致,并且可能比它可能更不明确:一方面, self
指的是“this”,“this what ”并不是天生显而易见的,相反,因为存在self::
表示“这个模块”,有人可能会推断出crate::
可能表示“其他一些箱子”,这实际上是线程中提到的混淆。
一种可能的解决方案是逐步淘汰self::
以支持mod::
。 然后我们将crate::
表示“在最近的封闭板条箱中”,而mod::
表示“在最近的封闭模块中”,这将是清晰和一致的。 我们也有可能解决的问题,它不可能指的内物品fn
通过引入范围,一个合格的方式在所有的fn::
前缀,以令人吃惊的平均“,在最近的封闭fn
”。 (我还没有考虑过更进一步是否有意义,还有像trait::
或impl::
。)
@glaebhoerl这是一个有趣的提议。 就我个人而言,我认为我已经想到了为绝对路径引入新语法并弃用现有语法的想法。 我不确定这种语法应该是什么样子,但我将在下面描述一种可能性(我知道之前已经提出过这种可能性)。
想象一下,我们有以下路径语法:
Path = AbsolutePath | RelativePath
AbsolutePath =
| `@` ID?
| `@` ID? `::` RelativePath
| `self` :: RelativePath
| `super` :: RelativePath
RelativePath = ID (`::` ID)*
在这种语法下,人们可以通过以@crate
开头来引用其他 crate 中的内容,例如:
use <strong i="13">@std</strong>::collections::HashMap;
可以只用@
引用本地板条箱,例如:
use @::something::in::my::crate;
(而且use self::something
和今天一样,无论好坏。)
这样做的好处是绝对路径与相对路径完全不同,这意味着我们现在拥有理想的属性,可以将use
的路径复制并粘贴到代码中,并且可以正常工作:
fn foo() {
<strong i="24">@std</strong>::cmp::min(a, b) // OK
}
今天不是这样,这肯定会不时让我感到困惑。
我们还消除了crate
周围的解析歧义,因此您可以执行pub Foo(crate @::MyType)
或其他任何操作,并且效果很好。
(一般来说,相对路径和绝对路径以相同的::
开头多次是痛苦的根源,这是事实。)
我不知道的一件事是@foo
是否是最好的。 我认为可行且我[]
:
[std]::collections
和[crate]::collections
// []::collections
看起来太奇怪了。我真的不认为我们应该为路径引入任何新的印记。 在::crate::foo
强制使用前导::
足以解决@glaebhoerl的评论并消除解析歧义。 它也更符合crate::
的预期心理模型——它是当前 crate 名称的替代品,而不是像self::
这样的路径前缀。
(一般来说,相对路径和绝对路径以相同的
::
开头多次是痛苦的根源,这是事实。)
我不确定你的意思。 我不认为任何相对路径都以::
开头,是吗?
@nikomatsakis @glaebhoerl与我是否喜欢你的建议无关(我实际上可以接受两者),我们可以坚持 RFC 吗? 它已经以多种方式来回讨论,我认为再次展开辩论对任何人都没有帮助。 共有 82 人对最新的 RFC 主题发表了评论(之前讨论过不少),很多人对此感同身受。 我认为在这一点上偷偷地在最后一刻更改提案,而不给他们审查更改的机会,这对他们来说是不公平的。
特别是我有点困惑,因为在 #44721 @nikomatsakis关闭了关于该功能的讨论,并提出了“请让我们只讨论实现”的论点。
@
表示法和[]
表示法都被提出过(我是两者的支持者)但他们最终没有成功,至少这是我的印象,由于用户的负面反应.
即使根本不存在前导::
可能与从前面的标识符开始并具有内部::
的路径混淆的情况,它在视觉上也不是很明显。
此外,它的暗示性较低。 @
是更好的助记符。 使用前导::
您必须想知道它是否类似于文件名路径,其中前导/
表示 root(如果您在 Unixy 系统上),或者它是否是标准缩写,其中没有前导这意味着“我们忽略了这个名字,因为它是相对的”。 稍加思考,您会发现前者更有意义,但关键是它需要稍加思考。 @
(或类似的东西)可以立即被编译器和编码器区分,从而更容易立即掌握正在发生的事情。
前导@
如何比前导::
更容易区分? ::
在 Rust 和 C++ 中已经是一个既定的机制!
@rpjohnst - 我在你回应的那句话中说的是如何! @
在视觉上是不同的。 扩展:它向你跳出。 在您的令牌流心智模型中,没有将领导定位与内部定位混淆的危险。
@
是一个全新的代币,没有任何意义,需要的不仅仅是“片刻的思考”。 将领先的::
与内部的::
混淆并不是一个问题 - 没有理由任何人都必须“花点时间”来驳斥领先::
的想法
@rpjohnst - 如果对::
含义进行了足够的培训(由 C++ 或 Rust 的经验提供),您的陈述是正确的。 我说的是可学习性和内在差异。 “在不同上下文中使用的相同符号”永远不会像“唯一符号”那样容易区分。
我可以接受这样一个论点,即在这样的用例中,不值得将@
作为一个独特的符号烧毁,其中有一个可以容忍的替代方案。
@Ichoran :我认为向 Rust 语法添加特定语义的新标记 ( @
) 不是一个可以掉以轻心的步骤,我有点怀疑我们太接近@nikomatsakis和其他人的提议。 一方面,因为我们无法在语言生命周期的后期将它重用于其他目的(我认为路径在代码中非常普遍,以至于@
标记可能出现在许多地方)。 我也想知道对 Rust 代码复杂性的感知有什么影响。 对于不习惯例如 C++ 的新手,我相信(但没有对此进行研究)Rust 是一种具有相当巴洛克式、令人生畏的符号的语言。 今年的战略目标之一是优化 Rust 的易学性和我认为的易接近性。 所以也许我们在看中@
时必须考虑这一点,因为直觉是它会在代码中脱颖而出( @rpjohnst我认为这是理所当然的问题)。 我是否足够清楚我的意思?
(随意更正或澄清我声称的任何内容,因为我根本没有时间密切关注关于 Rust 语法的讨论。)
@est31
不管我是否喜欢你的建议(我实际上都可以接受),我们可以坚持 RFC 吗?
基本上我同意。 我现在真的不想参与大型讨论——毕竟现在是 impl 时期! -- 但我确实想把@
想法“放在那里”在后台酝酿。 部分原因是我容易健忘,把事情写出来有助于我以后记住它们。
我的感觉是,此时正确的做法是:
::crate
用于绝对路径,只是为了解决解析歧义,因为它看起来像一个非常小的增量,实际上增加了整体的一致性。这就是我写评论的精神,尽管我想我没有说清楚。 也许将它保存在私人文件中会更好。 :woman_耸了耸肩:
编辑:另外,我知道@
和[]
是早些时候提出的,尽管我不记得之前是否提到过@::foo
符号是相对于当前的箱。 所以我并不是要声称是这个想法的作者。
OTOH,我提到的想法以前没有提出过,与其说是对 RFC 的修改,不如说是对它的扩展。 此外,“绝对路径的最终语法;在我们可以实际尝试各种选项的上下文中,还有更多的自行车棚需要完成。” 在问题正文中被明确列为未解决的问题。 我同意,一般来说,我们应该尽量避免重新对已接受的 RFC 提起诉讼,但我不认为这种情况与我们所遇到的情况相比,例如包含范围(呃)。
另请参阅此讨论主题:
https://internals.rust-lang.org/t/the-great-module-adventure-continues/6678
欢迎来到大模块冒险的另一集! 当我们最后一次见面时,我们勇敢的冒险者终于来到了传说中的土地,接受了 RFC #2126。 在那里,他们得到了短暂的喘息,并准备好从 Impl 时期开始。 那段时间,做了大量的工作,真正实现了模块系统的轮廓。 但是,还有一些琐碎的问题需要解决……这让我们进入了这个讨论主题。
用不那么花哨的语言:在 impl 期间,我们在实施“澄清和简化路径和可见性”RFC(以及一些相关的 RFC)方面取得了很大进展。 事实上,我们取得了几乎太多的进展——我们实施了几个不同的变体,我想开始讨论我们真正想要什么。
我希望有一天能够稳定这项出色的工作 =) 并且这将需要我们选择其中一个变体......因此线程。
我个人是@nikomatsakis 提到的@
语法的粉丝。 它简洁明了,而且一目了然。 我们将不得不推出某种新这里的语法,所以不如像保留名称的特殊字符crate
(啊)。
看起来我们现在可以处理第二个外部指针,特别是考虑到https://github.com/rust-lang/cargo/issues/1311现在已经解决(实际上它应该已经关闭)。 我可以通过一些指导和决定@
与crate
语法来解决这个问题。 想法?
为两个未实现的 lint 添加了跟踪问题。
我突然想到我们有一个小的兼容性问题:如果我们要让extern crate
成为隐式,那么在使该工作起作用时需要进行重大更改—— extern crate
强制链接 crate; 如果您在 Cargo.toml 中指定额外的 crate 而不是 lib.rs 中没有干净地链接在一起的额外 crate(例如,panic=unwind crates with panic=abort,或导出相同符号的 crate),这可能会导致错误。 我们是否确定这是一个没有问题的破损?
我突然想到我们有一个小的兼容性问题:如果我们要让 extern crate 变得隐式,那么在使该工作起作用时需要进行重大更改——extern crate 强制将 crate 链接起来; 如果您在 Cargo.toml 中指定额外的 crate 而不是 lib.rs 中没有干净地链接在一起的额外 crate(例如,panic=unwind crates with panic=abort,或导出相同符号的 crate),这可能会导致错误。 我们是否确定这是一个没有问题的破损?
到目前为止,我看到的唯一解决方案是仅在您从 crate 导入某些内容时隐式链接 crate,但这仍然存在一些问题。 除了简单地导出要导入的 rust 符号之外,还有很多方法可以让 crate 以多种方式公开功能,例如链接到某个本机库或导出#[no_mangle]
符号以解决本机库中的某些依赖项。 移除extern crate
后,强制链接此类 crate 的唯一方法是使其导出安慰剂锈符号以根据需要导入。 我不知道谁认为强制人们使用这种解决方法而不是坚持extern crate
是一个更好的主意。
是的,我们在 Firefox 中明确使用了这种模式——有一个顶层gkrust
板条箱,它只包含需要链接的板条箱的 extern crate 语句(这些暴露了 Firefox 调用的用 Rust 编写的 extern C 函数)
您仍然可以通过要求人们在 lib.rs 中use cratename;
来强制执行此操作。
为此目的使用#![link_crates(stylo,webrender)]
属性怎么样? 与extern crate
,它不会将板条箱添加到名称树中。 给它一个新名称会清楚地向读者表明您只包含用于链接的板条箱,不应删除该语句,而extern crate
应该删除。
这解决了相反的问题吗?
哦,我明白了,对于 2015 纪元的人来说,它可以让他们在不切换纪元的情况下升级他们的代码。
但这意味着 _everyone_ 将需要使用link_crates
密钥。 这并不理想。
为此目的使用 #![link_crates(stylo,webrender)] 属性怎么样? 与 extern crate 不同,它不会将 crate 添加到名称树中。
可以用作仅链接的板条箱,带有 Rust 符号的板条箱,或两者兼有的板条箱呢?
@whitequark如果您使用这些板条箱中的符号,您将免费获得链接,就像现在这样。 该属性将在使用站点上,因此您作为用户决定如何使用板条箱。
@Manishearth
但这意味着每个人都需要使用 link_crates 密钥。 这并不理想。
不,我的建议措辞不够好。 我想保持use cratename::item;
与link_crates
具有相同效果的部分完好无损。 link_crates
功能应该仅在您不需要板条箱中的任何项目但需要链接时使用。 如果您从板条箱中导入任何项目,您将获得类似于 RFC 提议的链接。
我只是不认为为此目的在您的代码中包含use cratename;
是好的,因为它会混淆 lint 和(最重要的)代码阅读器/编写器,因此认为应该有一个专门的功能用于合法的(但很少)用例。
@est31 Bikeshedding 关于link_crates
的语法,而不是将其作为属性,为什么我们不做类似extern crate foo;
事情?
@reep998
好主意! :微笑:
https://github.com/rust-lang/rfcs/pull/2166甚至引入了extern crate foo as _;
以避免将 crate 的名称带入仅链接 crate 的范围/模块中。
@est31 Bikeshedding 关于 link_crates 的语法,与其将其作为属性,不如我们做一些类似 extern crate foo; 的事情?
不过,从长远来看,重点是摆脱extern crate
语法。
@alexreg重点是在普通情况下不需要它。 这并不意味着它需要被完全根除,对于需要链接的 crate 的边缘情况,也许它仍然是一个很好的解决方案,而没有使用任何 Rust 项目。 (无论如何,只要编译器支持旧时代,它就会继续存在。)
@SimonSapin但是继续前进,如果它只是一个边缘情况,可能对其使用特殊语法是没有意义的,并且属性(如上所述)会更有意义。
我仍然认为use foo
或use foo as _
在这里应该足够了,真的
同意@Manishearth。
总结我对extern crate;
看法:
好处:
extern crate
在库的顶部为您提供了一个完整的已用板条箱列表。 现在对于普通的 crate,这与 Cargo.toml 不那么相关,但是如果您有示例,这非常有用,因为它为您提供了要导入的 crate 列表。 试想一下,如果您的示例只是导入了开发依赖项的一个子集会怎样? 当试图找出新 crate 的 API 时,这有很大的好处,也就是可学习性的好处。 另一方面,您可以提到extern crate
可能出现在 crate 中的任何位置,因此该列表不必详尽无遗,但对于示例而言,这不太相关。 如果我们愿意,我们总是可以将 extern crate 更改为仅在 crate 根中工作。缺点:
extern crate
是一个小烦恼,因为它意味着在添加板条箱时需要输入更多内容。 我认为这就是为什么很多人反对extern crate
但对我来说,这不是激励的原因。extern crate
是交易的一部分:我们放弃了extern crate
但获得了从自己的板条箱进口与从外部板条箱进口之间的区别。 这是一个更有用的功能,超过了 IMO 代码示例/测试的可学习性劣势。 这就是为什么我同意删除extern crate
的动机。extern crate 在库的顶部为您提供了一个完整的使用过的 crate 列表。 现在对于普通的 crate,这与 Cargo.toml 不那么相关,但是如果您有示例,这非常有用,因为它为您提供了要导入的 crate 列表。
我不明白这与这里的讨论有何关联; 这是反对已经合并的 RFC 的一点。
@Manishearth我更多的是在这里回复@retep998 ,他建议保留 extern crate。 不,一个点不是非法或不相关的,因为它反对已经合并的 RFC。 人们需要反思和了解决策的优缺点。 我们仍然可以例如从lib.rs
删除 extern crate,但为了人体工程学和易学性的好处(对于图书馆的用户,而不是它的作者),将它保留为hello_world.rs
。
这无关紧要,因为正在讨论的内容(在您回复的 Peter 评论中)是仅链接的板条箱; 这是一个足够利基的用例,“在顶部列出所有外部板条箱”是微不足道的好处。 特别是如果您的依赖项也是 _not_ 仅链接的 crate(这对于 Firefox 过去不是这样,但现在是这样)。
如果您的观点是关于将隐式 extern crate 事物不适用于测试(而不是专门针对仅链接的 crate)的更普遍的观点,那么这是一个有趣的观点,但我并不真正同意它,因为它会更多当它只在一半的代码中使用时会令人困惑。
所以,如果我没记错的话,这里唯一剩下的实现点是#48719。 现在有人处理吗? 如果没有,我可以试一试,我想……
是的,我们正在尝试 #50260
2018 年 4 月 28 日星期六,上午 9:15 Alexander Regueiro通知@ github.com
写道:
所以,如果我没记错的话,这里唯一剩下的实现点是
48719 https://github.com/rust-lang/rust/issues/48719 。 有没有人
现在解决这个问题? 如果没有,我可以试一试,我想……
—
你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/44660#issuecomment-385187379 ,
或静音线程
https://github.com/notifications/unsubscribe-auth/ABivSMyg6L4nQ1O7nMcvY4JCGjWKRiq3ks5ttJWhgaJpZM4PaPWi
.
@mark-im @Manishearth https://github.com/rust-lang/cargo/issues/1311也已完成,因此也许值得将该点更改为复选框并勾选它。 我很好奇:当 Cargo 没有被使用时,前进的方法是什么? (并不是说任何理智的人都会避开 Cargo ......)
@alexreg Cargo 用来告诉 rustc 重命名板条箱的机制对于不使用货物的人同样可以访问: --extern name_rustc_sees=path_to_dep.rlib
。
看起来我们很快就会完成整个实施阶段——事实上,当https://github.com/rust-lang/rust/pull/47992登陆时。 我错过了什么吗? 如果还有任何琐碎的事情要做,很高兴帮助推动这一进程。
是的,它正在路上。 我需要把我可能会早点做的结束
下周。
2018 年 5 月 3 日星期四晚上 7:51 Alexander Regueiro通知@ github.com
写道:
看起来我们很快就会完成整个实施阶段——当
47992 https://github.com/rust-lang/rust/pull/47992事实上。 是
我错过了什么? 如果有任何问题,很乐意帮助推动这一进程
鲍勃剩下的事情要做。—
你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/44660#issuecomment-386494018 ,
或静音线程
https://github.com/notifications/unsubscribe-auth/ABivSDYFonDWvxZEdxWXoykroaL2mJPxks5tu8I_gaJpZM4PaPWi
.
@Manishearth好东西。
@aturon与https://github.com/rust-lang/rust/pull/50260登陆,一切都实现了吗?
有人知道在 RFC之后提出的计划的链接吗? 哪个更类似于实际实施的内容? (在前奏中添加了--extern
板条箱的进口,等等)
找到它: https :
既然这是一个如此重大的变化,也许应该更新 RFC?
RFC 通常不更新; 它们不是最终规范。 他们是一个
共识建立工具。
2018 年 6 月 18 日星期一晚上 9:43,谁? 我?! 通知@github.com写道:
既然这是一个如此重大的变化,也许应该更新 RFC?
—
您收到此消息是因为您订阅了此线程。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/44660#issuecomment-398247665 ,
或静音线程
https://github.com/notifications/unsubscribe-auth/AABsij-Iwwb7vf4qBrsq9KFFqhuIbkVBks5t-Fc3gaJpZM4PaPWi
.
@mark-im 那篇文章符合 RFC 的精神。 将 RFC 的摘要与该帖子进行比较,除了一些细节之外,它大体相同。 在 RFC 中,团队决定进行完全不同的更改,但这不是其中之一。
这一切都是真的,但最好将所有内容集中在一个地方。 不过,我确实理解其中的后勤挑战……
🔔 🔔 请注意, 2018年初的
@aturon最近一次更新,也是模块工作组的最后一次会议,结果是https://internals.rust-lang.org/t/the-great-module-adventure-continues/6678/205 ,里面特别说“缩小到一个核心提案,有两个变体”。 据我所知,这仍然是正确的。 我的印象是 nightly 已经通过功能标志实现了两者,以支持对两者的实验。
该版本似乎选择了两个变体中的一个,选择了支持而没有功能标志,并将其记录在版本指南中。 这是在哪儿讨论的? 因为据我所知,模块工作组和 lang 团队都没有参与其中。
请参阅https://internals.rust-lang.org/t/relative-paths-in-rust-2018/7883以获取从 2018 年预览版构建的新提案。 特别是,这个提议在根模块和子模块之间提供了更多的一致性和统一性,并且在use
语句中和在代码中直接使用路径时都使用相同的名称解析。
嗨, ::some::path
与crate::some::path
,我只需要 2 美分 - 我更喜欢后者,主要是因为它更容易阅读纯英语,并且不会留下疯狂的左挂标点符号。
请看一看并在这里留下反馈!
我希望这就是你的意思。 在审查了期货箱的一个大变化之后,其中所有pub(crate)
都被更改为crate
,我更加确信在导入和可见性中都使用crate
修饰符感觉不自然和混乱。
crate enum Either<T, U> {
A(T),
B(U),
}
当两者一起使用时,我发现它特别令人困惑:
crate use crate::foo;
正如我在lint 问题中提到的pub(crate)
转换crate
。
(注意:我不会评论更改的任何其他部分,这似乎有利于一致性,只是从pub(crate)
更改为普通的crate
。)
@seanmonstar由于在下一版预览中提议对模块系统进行额外更改,我预计crate::foo
将变得更加罕见,而crate use crate::
似乎是一种特别罕见的情况。
使用 2018 年初始预览版中的模块系统,您甚至需要编写crate::
以获取更深入您的 crate 的引用。 在所提出的模块系统,你只需要crate::
在您的箱子了引用(例如,从foo.rs到lib.rs,或从富/ bar.rs到foo.rs),但不是在你的箱子下来引用(例如,从lib.rs到foo.rs,或从foo.rs为foo / bar.rs)。 通常,我希望重新导出(无论是通过pub use
还是crate use
)从更高级别模块中的更深层模块重新导出某些内容,而不是相反。
所以总的来说,我会惊讶地看到crate use crate::foo;
。
然而,在我正在进行的一个项目中,我恰好遇到
目前:
// in filter/mod.rs
pub(crate) use ::generic::{Combine, Func};
// in filters/foo.rs
use ::filter::{Filter, Func};
lint 会希望我将其更改为:
// in filter/mod.rs
crate use crate::generic::{Combine, Func};
所以,我并不是想提出一个没有人会遇到的假设。 它是真实的。
我完全同意@seanmonstar。 我们不要重载这个关键字,除非我们必须(我们没有)。
是的,你是对的,再出口_通常_会冒泡,但正如肖恩概述的那样,被_横向_再出口也是一回事。 这也是我正在考虑为伺服媒体板条箱做的事情,因为文件被很好地分割,但这只是意味着在我们所有的节点实现中都有很多常见的导入。
是否可以继续声明模块中使用的内容并可能需要显式使用,也许作为 crate 属性? 我更喜欢通过查看源文件来了解其中的范围。 在源文件的开头有几行根级导入有助于为其中实际发生的事情提供一些上下文,而不仅仅是在范围内隐式包含所有外部依赖项,并且在重构时有很大帮助。
在我的一个板条箱上尝试了转换后,我想像我看到的其他一些人一样提到这个,我不相信使用crate
作为可见性修饰符而不是pub(crate)
一种提升。 我的理由是 crate 绰号被广泛使用,只是把它贴在物品前面会让它有点乱(它让我想起你在某些语言中得到的关键字汤,比如 Java 的public static void main()
--至少 Rust 最后有返回类型)。 pub(crate)
至少保留了pub
以使crate
在此上下文中处理可见性更加明显。
这是我刚刚遇到的另一个实例,它在可见性修饰符和路径中结合了crate
关键字,这似乎比crate use crate...
实例更有可能。
当前的:
pub(crate) struct Bar {
pub(crate) foo: ::Foo,
}
pub(crate) struct Baz(pub(crate) ::Foo);
有了这个跟踪问题的变化:
crate struct Bar {
crate foo: crate::Foo,
}
crate struct Baz(crate crate::Foo);
我个人认为新的方式比当前的方式更令人困惑。
当我第一次阅读 RFC 以将pub(crate)
转换crate
我认为这听起来很简单。 pub(crate)
与该领域的其他相关 Rust 语法相比看起来很奇怪。
但...
在将一个小的 Piston 游戏转换为 Rust 2018 并亲眼目睹之后,我必须承认我很同情@seanmonstar和其他人的评论,即在各处散布裸露的crate
在认知上是不和谐的。 我不确定随着时间的推移我是否会自然地习惯这一点。
正如其他人所说,感觉就像关键字在两种上下文中的含义都非常不同。
use crate::menu::{Sound, Volume};
crate mod color;
...
/// A type for storing text and an associated color it should
/// be drawn as.
crate struct ColoredText {
crate color: types::Color,
crate text: &'static str,
}
我想说清楚我真的很喜欢这个提案的其余部分(模块系统更新)。
我很同情pub(crate)
看起来有点笨手笨脚,也很奇怪,但裸露的crate
感觉有点不合适。
我们可以在这里考虑一个不同的关键字而不是重用crate
吗?
@neon64建议internal
听起来很合理,但可能还有其他的。 由于我们可以在 Rust 2018 中添加关键字,我们现在有机会考虑这一点。
internal
pub(crate)
对我来说似乎比
int
怎么样? :P
内部( ins
),内部( int
),受保护( pro
),本地( loc
),秘密( sec
),内部( inn
)有很多替代crate
关键字的方法。
但是, int
会不会让 C/C++ 开发人员感到困惑? (整数关键字)
作为程序员,当您看到 pub 时,您将其视为公开的,如果您想引入另一个可见性级别,那么您需要将其用作形容词以保持一致。 据我所知, pub 最初代表发布,在这两种情况下, pub(crate) 感觉更自然。 Crate 只是奇怪的关键字。
我认为最好保留 pub(crate) 原样或添加形容词的缩写。
此外,我认为命名的困难源于 pub 是缩写的事实,如果它是公开的,我认为将其称为私有或内部并忘记它不会有问题。
就我个人而言,我只是没有看到pub(crate)
。 语法一目了然,与实际的 Rust 一致。 我认为您不必经常输入 5 次额外的击键就成了问题。
@UtherII
我们需要pub(crate)
的短名称的原因是因为pub
当前使用的很多(甚至可能是大部分)将被替换。
在 Rust 2018 中,将pub
用于有效的私有项(因为它们出现在私有模块中)将是一个警告。 对于此类项目,应该使用pub(crate)
代替。 这个约定将提高代码的可读性:当且仅当它被标记为pub
,一个项目对其他 crate 可见,而目前它是否对其他 crate 可见可能一目了然。
抱歉,我不小心为此创建了一个新问题,而不是响应此线程。 糟糕,我对 github 还是很陌生,只是点击了一个按钮,这让我登录到了我认为在此处做出响应但实际上创建了一个新问题的内容。 我把我在新问题中写的内容贴在这里,我的新问题可以删除,抱歉。
看到版本手册建议人们在这里留下反馈,我决定这样做。
我真的不介意 crate:: 或 :: 从 crate 根访问元素。 :: 已经是语法,所以如果可以同时使用 crate:: 和 :: 我认为两者都应该使用。 我的看法是,关于路径的新建议的 crate 系统本质上等同于旧语法,唯一的区别是您不再需要使用 extern 关键字,并且事物更易于访问而不是需要明确使用它们在子模块中,它们基本上是隐式导入的。
唯一的其他添加似乎是您使用 crate:: 而不是 :: 开始 crate 根。 我更喜欢只从 :: 开始它,因为这与我最初学习它的方式一致,但是我可以看到那些没有学习过模块系统的人却发现从 crate:: 开始它更直观。 为什么不允许两种语法形式? 是否有某种原因使两者都不可行? 如果两者都能得到支持,我完全赞同支持它们。 如果只能支持一个,我更倾向于 :: 就像我已经习惯的那样,尽管新手可能更容易将其作为板条箱来学习 :: 并且我可以简单地更新我对它的理解是这样,所以也许我的动机是自私的。
所以本质上,我最终并不在乎,但我个人更喜欢 ::,但我认为同时支持两者是理想的,尽管如果必须选择一个并且人们认为从 crate:: 开始它对新手来说更好,那么我不不反对这个。
#[path]
应该如何与 Rust 2018 中的嵌套模块一起使用? (https://github.com/rust-lang/rust/issues/35016#issuecomment-409185342)
IIUC,现在,给定两个文件src/lib.rs
和src/bar.rs
,没有X
可以替换为:
mod foo {
#[path = "X/bar.rs"]
mod bar;
}
这样将找到模块bar.rs
,因为bar.rs
的路径将始终是src/foo/X/bar.rs
,这是无效的,因为目录foo
不存在。
由于我们正在为pub(crate)
更换提供一个好名字,而核心团队仍在寻求反馈,因此我想分享我的经验并提供建议。
在我写的一个板条箱中,我发现到处输入pub(crate)
令人气愤。 所以我只是将它缩短为pub
并无意中导出了许多不需要在板条箱外可见的符号。 哎呀。 😛(在我的特定情况下,这不是一个真正的问题,因为 crate 是内部的并且未发布,但仍然!正确性的方便。)所以,是的,我坚信我们需要比两个关键字的混搭更好的东西来传达 crate 级别的可见性.
但我不相信crate
是它的正确关键字(请参阅上面其他人对这个主题的反馈),而且我觉得其他一些建议的关键字从角度来处理问题有点错过了重点板条箱根; 问题在于模块的角度,即包含关键字的特定代码行。 换句话说,代码不是试图提供“板条箱位置”,而是试图从定义它的模块中导出引用。
从这个意义上说,我喜欢关键字export
(即使它可能与extern
混淆,但也许这没有实际意义,因为extern crate
已经死了?) export struct Foo;
看起来非常可读,并与其他一些语言(ish)保持一致。 我无法在此 RFC 或其他地方找到任何提及export
作为关键字的内容。 所以也是如此。
为了完整起见,它涵盖了@johnthagen等人提出的用例:
export use crate::generic::{Combine, Func};
// Or even better using relative paths
export use ::generic::{Combine, Func};
export struct Bar {
export foo: crate::Foo,
}
export struct Baz(export crate::Foo);
use crate::menu::{Sound, Volume};
export mod color;
// ...
/// A type for storing text and an associated color it should
/// be drawn as.
export struct ColoredText {
export color: types::Color,
export text: &'static str,
}
尽管如此,我赞成用火杀死pub(crate)
。 我什至更喜欢crate
,FWIW。
@parasyte我看到export
是它可能与“这个板条箱出口____”(这就是pub
的用途)混淆,但我明白你是如何提倡不同的视角。
似乎大多数人都同意pub(crate)
并不理想,而且许多人担心现在在其他上下文中使用的名词关键字crate
作为替代品可能会很刺耳。 确保我们已经充分考虑了其他(可能是新的)关键字似乎是在 Rust 2018 将其固定下来之前很好地利用时间。
如果这仍然可供讨论,我还没有听到任何“官方”反馈?
为了按照@parasyte的建议引入更多词(我同意@johnthagen 的观点,即export
看起来更像是pub
不是pub(crate)
):
shared use ::generic::{Combine, Func};
shared struct ColoredText {
export color: types::Color,
export text: &'static str,
}
global use ::generic::{Combine, Func};
global struct ColoredText {
export color: types::Color,
export text: &'static str,
}
我们也可以跟随 Java 的脚步并使用诸如protected
,但我不确定这是否特别容易凭直觉理解。 还有local
(就 crate-local 而言),但我认为global
实际上不太可能混淆(例如, local
可能是 _file_-local)。
人们会如何看待pub(cr)
甚至只是cr
?
使用crate
似乎太好了,不能放弃。 它已经是一个关键字,它之前在extern crate
中的使用正在消失。 它的其他用途已经与可见性pub(crate)
。
如果你用 crate 作为形容词稍微眯起眼睛,听起来并没有那么令人不安。 诸如“house”之类的词可以用作形容词就好了。 IANA英语教授。
我认为重新导出一个板条箱可见的物品并不是什么大问题。 就我个人而言,我只在定义它的模块的直接父项中重新导出了一个项目,这意味着您(可能)想要使用self
而不是crate
(seanmonstar 的代码组织案例尽管如此)。 例如。
mod detail {
crate struct Foo;
}
crate use self::detail::Foo;
使用 crate 作为可见性结合类型的绝对路径(再次使用 seanmonstar 的示例)确实看起来更有问题: crate struct Foo(crate crate::Bar);
而不是pub(crate) struct Foo(pub(crate) ::Foo);
。 我唯一的希望是这个结构不流行,因此转换不会产生这种板条箱汤。 用户可以通过显式导入来避免这种情况:
use crate::Bar;
crate struct Foo(crate Bar);
我确实喜欢share
或类似的建议。 give
, provide
, deliver
, offer
, serve
, post
, forward
.. . 如果一定是形容词,这些都可以加上后缀: shared
, givable
, providable
等等。
暂时选择 JavaScript,ES6 甚至没有内置于语言中的包与模块的概念。 只有模块。 ES6 中的export
关键字总是从模块中导出引用; 如果它想使用它,那么它取决于另一个模块到import
的路径引用。
这分别与pub
和use
没有太大区别。 我想这就是使用export
关键字会引起一些混乱的地方。 pub(crate)
实际上是一种利基。 这就是为什么我过去选择只使用pub
的原因。 ;(
crate
可见性修饰符的问题已提取到#53120。 进一步的辩论和决定应该在那里继续。
mod.rs
更改的问题已提取到#53125。 进一步的辩论和决定应该在那里继续。
extern crate
弃用以及use crate_name::foo
和crate_name::foo
Just Work™ 的问题已提取到https://github.com/rust-lang/rust/问题/53128。 进一步的辩论和决定应该在那里继续。
选择模块路径系统的问题已提取到https://github.com/rust-lang/rust/issues/53130。
将这个问题的所有部分提取到单独的问题中; 我在此关闭这个。
@Centril : https : //doc.rust-lang.org/unstable-book/print.html#extern_prelude链接在这里。 这是在哪里讨论的? 如果确实缺少此信息,您能否将其添加到 OP 中?
@sanmai-NL 你能刷新我对“外部前奏”是什么的记忆吗?
如果它只是能够执行use some_crate::foo::bar;
那么应该是https://github.com/rust-lang/rust/issues/53128。
@sanmai-NL 我相信这个问题主要是为了诊断。
extern_prelude
是crate_name::foo::bar
use
(导入)路径之外的use
。
@Centril
你能回忆一下“外部前奏”是什么吗?
一般来说,“prelude”当前用于整个 crate 范围内的所有名称,而不是附加到特定模块。 (实际上有很多。)
@petrochenkov那么,与此相关的“外部”前奏是什么?
@alexreg
用--extern
传递的 crate 是整个 crate 的范围,而不是附加到任何特定模块。
如果这些信息块,无论多么不稳定,都记录在某些官方文档来源中,那就太好了。 特别是如果有外部提及该概念,例如在 Unstable 书中。 不过,我并不是说实现这些概念的维护者应该这样做。
@petrochenkov谢谢,有道理。
将这个问题的所有部分提取到单独的问题中; 我在此关闭这个。
@Centril在当前测试版链接中跟踪问题。 你会用最新的信息更新原始评论,这样人们就不必解释评论吗?
最有用的评论
这是我刚刚遇到的另一个实例,它在可见性修饰符和路径中结合了
crate
关键字,这似乎比crate use crate...
实例更有可能。当前的:
有了这个跟踪问题的变化:
我个人认为新的方式比当前的方式更令人困惑。