Rust: `..=` 包含范围的跟踪问题(RFC #1192)——最初是 `...`

创建于 2015-09-04  ·  331评论  ·  资料来源: rust-lang/rust

当前状态

我们计划将包含范围和模式的语法更改为..= 。 模式中的...语法是稳定的,并且将暂时(默默地)弃用; rustfmt 可以将...重写..= 。 这是经过多次讨论后得出的。 请参阅此评论以获取理由。

在这个线程中不应该有更多的语法讨论您阅读了此处的所有现有评论及其基本原理用户论坛内部论坛上提出任何不同的独占范围语法建议。 值得注意的是,打破向后兼容性是不可能的。

采取的步骤

B-RFC-implemented B-unstable C-tracking-issue E-mentor T-lang T-libs disposition-merge finished-final-comment-period

最有用的评论

lang 团队在今天的会议上再次讨论了这个特性,大致得出了以下矩阵:

  • 仅支持模式中的...和表达式中的..是站不住脚的设计; 它导致用户期望语法可以正常工作。

  • 在这两个地方都允许.....会有所帮助,但一对一的问题是一个真正的问题; 我们没有人急于收到有关人们花费数小时来追踪错误时期的报告。

  • 移动到..=..不太美观,但避免了上面非常实际的实际问题。 我们也可以以非常温和的方式推出它:首先引入..=作为替代语法(rustfmt 可以重写),只有在它变得惯用之后,才弃用...

如果您不知道,团队认为..=..是我们前进的最佳途径。 这个问题也被讨论到了不太可能提出新论点的程度,所以我们准备冒险:我们正在寻找愿意为两者实现..=符号的人模式和表达式,然后我们将去 FCP!

所有331条评论

也许a..b|a..b]

我认为这将为将来出现新的不可预测的错误开辟道路,因为一个简单的错字(.. vs ...)。 如果它是......更好(4个时期)。 这样,人为因素就不容易出错,imo。

我认为https://github.com/rust-lang/rfcs/pull/1592https://github.com/rust-lang/rfcs/pull/1582结合使用..=语法代替。 除非有人能想到比(head..., tail)更好的语法来在更大的元组前面扩展元组。

我发现这个问题是因为当我打算使用独占范围时,我的代码中有 _off-by-one- dot _ 错误。

👎 用于...语法。 我认为有一个容易打错的语法会导致一个错误的错误。

不过这个功能很有用,所以我很乐意使用不同的语法,例如..=

这是一个开放问题的语法吗? 由于...已经在 match 语句中,我认为这艘船已经航行了。

我个人更喜欢...包含的范围,但是因为已经有..独家版本,我看到了问题的可能性。 在查看 #23635 之后,虽然我宁愿弃用..并且只允许...

我经常使用包含范围来等效于 C 类 for 循环for i in 0..foo.len()在它完全适合的地方,所以我更喜欢留下那个(我需要这个,因为 Rust 的迭代器是“一维的”并且经常与二维数组或非线性迭代一起使用太笨拙)。

包含范围的溢出问题看起来很愚蠢,但实际上我从未遇到过这个问题,因为 Rust 与usize以外的任何类型一起使用都很烦人。 如果我在创建范围for i in 0..(len as usize) ,那么无论如何我都必须在循环内使用i as usize六次。

由于这种语法仍然是功能门控,我希望这艘船还没有航行。

考虑到 swift 使用...来表示包含和..<表示不包含范围,使用..=来表示包含似乎很合理。

我没有任何有用的见解,但我希望包含范围退出“实验”状态。 在我通过示例学习 Rust 时,我发现了一个可以从中受益的片段:

fn fizzbuzz_to(n: u32) {
    for n in 1..n + 1 {
        fizzbuzz(n);
    }
}

向上 ? 😄

我想为a ..= b语法和广义范围编写一个 RFC。 我已经开始讨论如何在标准库中表示这些范围。

恕我直言..= 看起来很奇怪。 Swift 的 ... 和 ..< 方法对我来说看起来更好,因为我更喜欢省略号而不是两个点 - 省略号代表省略,我们省略了范围开始和结束之间的数字。

我仍然认为......而且..已经足够好了。 你有 1 个字符差异,所以这个错误比 +/- 或 x/y 或其他更难犯。

由于我自己之前误解了这一点(因此删除了我的评论):

根据 Rust 的 RFC 流程,该提案已经在RFC 拉取请求 1192 中进行了审查、讨论和批准。 本期跟踪之前在那里决定的内容的实施情况。 讨论涵盖了人们在这里提出的许多观点:替代语法(包括没有新语法)、与 Ruby 类似运算符的对比等。

如果您强烈认为该功能应该有所不同,我认为您需要通过相同的 RFC 流程来处理它,因为这就是对语言进行更改的方式。 但这个问题不是那个地方。

@jimblandy也许我们应该让@nikomatsakis将礼貌的提醒和指导编辑到“真正的

@shepmaster添加到用于归档 _all_ 跟踪问题的模板中可能是一件好事。

提名讨论/可能的 FCP

我们在@rust-lang/lang 会议上讨论了这个问题。 人们普遍对这个功能感到不满——我们考虑过弃用,但决定暂时推迟。 对...反对意见主要有两个:

  • .....之间容易混淆;
  • @aturon一直认为拥有更“

为此,我们想知道是否有人愿意推动 RFC 启用更通用的语法,让人们精确地指定下限和上限是包含还是排除。 我认为@aturon会很乐意与某人合作处理这样的 RFC。

我知道我停滞了一段时间,但我最近打开了一个讨论线程,讨论如何在 libstd(上面链接)中表示那些完全可用的范围,但没有人发表评论:(

通过对上述内容的一些输入,我很乐意为新的 RFC 提供帮助。

我最近打开了一个关于如何在 libstd(上面链接)中表示那些完全可用的范围的讨论线程,但没有人评论:(

这在某种程度上反映了它们的用处。
虽然有任意包容独家范围听起来像一个不错的主意,我敢肯定一切,除了..和少得多的程度...永远不会被使用。

@杜尔卡

我知道我停滞了一段时间,但我打开了关于如何在 libstd 中表示那些完全可用的范围的讨论线程(上面链接),但没有人发表评论:(

这看起来与我们想到的方法大致相同,是的。


@彼得罗琴科夫

虽然拥有任意的包含-排除范围听起来是个好主意,但我很确定除了 .. 之外的所有内容......而且在较小程度上......永远不会被使用。

老实说,我同意,但我仍然认为可能值得追求更通用的语法。 特别是,我认为...是次优的,但是如果我们转向..=或更明确的东西,那么做一些更一般的事情可能并没有什么坏处,即使很少用过的。 也就是说,如果我们把它系统化,它看起来并不难学,而且肯定不会混淆.....意味着“更多的数字”。

这看起来与我们想到的方法大致相同,是的。

哪一个? 我在我的帖子中提出了几种替代方案。

我经常想遍历包含的范围并且真的很喜欢输入0...x而不是0..(x + 1) 。 我知道这可能会引入一对一错误,但我们有哪些替代方案?

假设 Rust 的语法可以在没有副作用的情况下自由更改,我只看到一些明显的模式:

照原样

1..4 // 1, 2, 3
1...4 // 1, 2, 3, 4

恕我直言,这是一个不错的解决方案,也用于模式匹配。

借用数学

[1, 4] // 1, 2, 3, 4
[1, 4[ // 1, 2, 3
]1, 4] // 2, 3, 4
]1, 4[ // 2, 3

这是最完整的语法,但打破了相同数量的左括号和右括号规则,并且在视觉上更难解析。

借用 Python

1:1:=5 // 1, 2, 3, 4, 5
1:1:<5 // 1, 2, 3, 4

这是一种已知模式,也可以包含步长。 我不知道 RFC 流程是如何工作的,但我认为在谈论范围时也应该考虑步长。

当步长不是本次讨论(或未来讨论)的一部分时, ..=..<似乎非常合理!

更新:我认为..=..<将是一个非常好的解决方案。 保持步长作为适配器更有意义。

此讨论是否应包含降序范围? 当前反转范围的解决方案非常令人困惑(但如果我们有包含范围,则可能不会)。

例如,你能不眯眼地阅读和理解吗?

for i in (1..l.len()).rev() { ... }

编辑:使用 GitHub 的字体更令人困惑,因为l看起来像1

我认为负步长就足够了。

我们可以使用 Matlab 语法a:ba:step:b

2016 年 11 月 4 日 00:50,“Ott” [email protected]写道:

我认为负步长就足够了。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment -258344460,
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3n3kwnGH6POQb4dGwCwJ8yOGqPSBQks5q6rmDgaJpZM4F4LbW
.

@durka那么当前..的等价物是什么,其中没有ab ? 只是:

我在 RFC 中没有看到的一些内容:是否为这些字段考虑了不同的名称?

如果有不同的类型,当它们具有不同的含义时,使用不同的字段名称可能很有价值。 例如,“range.start”是所有类型的“下限”。 但是“range.end”有时是包容性的,有时是排斥性的。 “结束”和(稻草人)“最后”之间的区别使这一点更加清晰。

(当然,如果放弃不同类型以支持 Range>...)

我认为包含范围仍然应该实现 std::collections::range::RangeArgument。

pub trait RangeArgument<T> {
    fn start(&self) -> Option<&T> { ... }
    fn end(&self) -> Option<&T> { ... }
}

然后

impl RangeArgument<T> for RangeToInclusive<T> {
   fn end(&self) {
     Some(self.end+1)
   }
}

这样fn foo<T, R: RangeArgument<T>>(arg: R)可以采用包含或半开范围。

@durka a:b 语法的问题在于它与类型归属不明确。 您是要变量b还是类型b ? 显然,作为优秀的 Rust 程序员,我们将我们的类型大写,但编译器无法推断出这一点。

.. 带有数学定义的运算符(基于@duesee注释):

[1..4] // 1, 2, 3, 4
[1..4[ // 1, 2, 3
]1..4] // 2, 3, 4
]1..4[ // 2, 3

使用(基于@0tt示例):

fn fizzbuzz_to(n: u32) {
    for n in [1..n + 1] {
        fizzbuzz(n);
    }
}

在这种情况下,我们使用..作为提示,但边界由[]

@adelarsq :在 Rust 中,我们不需要不包含开头的范围。 但是括号语法只有在允许的情况下才有意义。 另外,括号语法已经被使用。

我认为..=是包含范围的最合理的选择。
很容易在视觉上与..区分开来,而...则不然。 在表示.. ...时输入..=
(这与在 C 中意外键入if(a = b)而不是if(a == b)相当,无论是在视觉上的可察觉性还是潜在的错误)。
并且..=很容易记住,因为它具有象征意义( i ..= j表示范围i .. ji = j )。

似乎主要的抱怨是.....太相似
那么,对于包含范围的....呢? 它应该仍然看起来像一个范围,正如我所说,似乎没有人介意需要一个额外字符的解决方案。 它是否比..=更不稳定是值得商榷的。
for i in 0....10 { println!("just a thought"); }

如果默认行为包括..! 将使用运算符(几乎作为否定)。

....在于,如果...真的存在,那会有些混乱。

我也真的不喜欢... ,因为与Ruby完全相反。

到目前为止,我认为最好的选择是..=

@adelarsq....运算符将替换...运算符,因此,如果您尝试执行..并添加额外的. ,它将是一个编译时间错误,如果你试图做....并且忘记了一个点,那也会是一个错误。

由于在模式匹配中, ...用于匹配包含范围,因此也使用...进行包含范围表达式是有意义的。
对于带步骤的范围,我更喜欢 Haskell 语法,例如1,3..9 => [1,3,5,7]

对于带有 step/reverse 等的范围,我更喜欢一个好的老式函数(某种Range构造函数)而不是复杂的文字。

我对四点.... (虽然..=恕我直言也很好)。 为了一致性,它也可以在模式匹配中被允许(最终模式中的...可能会被弃用)。

对我来说..=作为....没有的视觉意义。

我刚刚注意到一件事:

在数学中,你可以写出∀ i: 0 ≤ i < 10这将转化为

for i in 0 ..< 10 { }

这是一致的。

但是,语句∀ i: 0 ≤ i ≤ 10将转换为

for i in 0 ..= 10 { }

在这里,≤ 转换为 =,感觉不一致。

这可能是自行车棚,但是

for x in 0 ..<= 10 { }

感觉更正确。 这可能是由于我的 C 背景在哪里

for (unsigned int i = 0; i <= 10; ++i) { }

翻译成“只要i小于或等于10就做某事”。 在 CI 中,不喜欢在循环条件中使用== ,因为有可能跳过该值并以无限循环结束。 这在 Rust 中不会发生,但是将for i in 1 ..= 10成 C 可能正好表明了这一点。

更进一步,

for i in 0 <..<= 10 { }

不言自明。

编辑:这是一个糟糕的反向示例,旨在说明仅使用=可能会令人困惑。 已删除,因为它比建设性更令人困惑。

@duesee >=..>是如何不言自明的? 不应该是<=..> (<= 10 and > 0) 吗?
IMO 这不是不言自明的,它是神秘的,而且作为运营商来说太长了。
(任何操作符都不应超过 3 个字符 IMO)。
顺便说一句,我们已经有了一种表达反向迭代方向的方法: .rev()
我们只需要包含范围的运算符,也许.step_by()
对于该步骤,语法可以是a .. b | s (对于包含范围: a ..= b | s )。

@norru :您的示例for i in (1..l.len()).rev() { ... }非常不切实际,因为大多数情况下您会使用切片( for x in arr[1..].rev() { ... } ),但即使您被迫使用索引样式的迭代(基本上只有当您修改不在i处的数组元素时,我发现它根本不难阅读。 (但是当参数不是文字数字时,我通常会在..周围留下空格: (1 .. arr.len()).rev()

>=..>在 Rust 运算符中

但我确实很喜欢..<= (编辑:呃,除了match看起来像<= 0 => :()

  • 它与普通的..截然不同,
  • 它没有..=+=内涵,
  • 即使与 Swift 的..<在逻辑上也是一致的。 两种语言有可能融合!
  • 最重要的是,很明显你得到的范围内的数字小于或等于上面的数字。

@pornel : >=..> more species of fish in Rust operators!呵呵:-)

@Boscop :如果您像数学中的定义一样阅读它,10 >= i > 2 。 对于您的其余回答:我完全同意。 第二部分是为了重新考虑..=..<=的动机,以免为未来的扩展引入拦截器。 我将相应地编辑我的答案。

还可以在..符号上获得警告或错误的标志

我不希望..出现在我的代码库中的任何地方

我想为..=再投一票

..<..<=的缺点是它们已经是有效的代码(右开独占范围与另一个值进行比较)。

@thepowersgang

..< 和 ..<= 的缺点是它们已经是有效的代码(右开独占范围与另一个值进行比较)。

虽然是真的,但在实践中这似乎不太可能成为问题,不是吗?

我非常喜欢...而不是这里的其他建议..但是如果我必须选择一个替代语法,它会是..=

@nikomatsakis

我反对..<..<=选项纯粹是因为它们使获取语言语法的直观模型的过程不成比例地复杂化。

就个人而言,我发现它们至少和涡轮鱼一样丑陋和不优雅。

我会使用..表示正确独占和..=表示包含,这是视觉优雅、易于直观掌握的语法规则以及使两者难以混淆之间的最佳平衡。

...真的与..没有区别吗? 为什么我这么喜欢它?

@tshepang

我喜欢...因为它在美学上很吸引人...但我反对它,因为我担心它有可能导致难以注意到的错误,类似于编写if (x = 2) {而不是if (x == 2) { C/C++ 中的

@ssokolow

IMO 可以通过 linting 或选项标志更好地解决。 我认为在单个文件/项目中混合符号没有多大用处。

也更喜欢....而不是其他选项,宽度/间距加倍应该使它足够明显,特别是考虑到它们两侧都有符号,这将使负空间比孤立更明显。

@ssokolow

我会选择 .. for right-exclusive 和 ..= for inclusive 作为视觉优雅、易于直观掌握的语法规则以及使两者难以混淆之间的最佳平衡。

这个对我有用。 主要的症结在于我们是否需要其他情况的语法(例如, <..<= )。 我个人认为....=涵盖了 99.5% 的情况。 我认为主要的用例是像drain这样的 API,我们目前在那里采用了一种

抄送@rust-lang/libs

我们可以将不常见的情况留给使用直接构造范围
结构文字。

2017 年 2 月 22 日星期三下午 4:50,Niko Matsakis通知@github.com
写道:

@ssokolow https://github.com/ssokolow

我会选择 .. for right-exclusive 和 ..= for inclusive as the best
在视觉优雅、易于直观的语法规则之间取得平衡
掌握,使两者难以混淆。

这个对我有用。 主要的症结在于我们是否想要一个
其他情况的语法(例如,<..<=)。 我个人觉得..和..=
涵盖了 99.5% 的案例。 我认为主要用例是像 Drain 这样的 API,
我们目前在那里采用了一种独特的方法
https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
.

抄送 @rust-lang/libs https://github.com/orgs/rust-lang/teams/libs


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-281815665
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3n-aKwYKFq4VI9RizL0GkzXXSjTPwks5rfK2ngaJpZM4F4LbW
.

我认为..=也会以模式提供吗? 那里现有的...语法会怎样?

它可以被弃用。 但它的存在是一个非常强大的先例
使用它,至少作为速记。

在星期三,2017年2月22日在18:02,andrewtj [email protected]写道:

我认为..= 也会以模式提供吗? 会变成什么样
现有的...语法有吗?


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-281834007
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3nw_DaOMNxuIKw6ZFfXJW95QyijY4ks5rfL6DgaJpZM4F4LbW
.

@durka @andrewtj我认为我们会弃用它。

..=可以用作与+=相同意义上的运算符。
我建议使用潮汐~ ,例如0~9'A'~'Z'

..=对应什么操作? -显然是不可行的,因为
1-9 == -8

2017 年 2 月 22 日,星期三,晚上 8:04,刘俊峰通知@github.com
写道:

..= 可以用作与 += 相同意义上的运算符。
我建议使用~,例如0~9,'A'~'Z'。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-281856846
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3n7N2dM4DAzc_uc5JdHit4IJgyvYGks5rfNsPgaJpZM4F4LbW
.

@durka ..=看起来就像赋值运算符,用例肯定很少见。 ~是潮而不是子。 使用...也可以。

impl Fill for Range<String> {
   fn fill() -> String { ... }
}
impl FillAsign for RangeAssign<String> {
   fn fill(&mut self) { ... }
}
(String::new("abc") .. String::new("f")).fill()  // "abcdef"
(String::new("abc") ..= String::new("f")).fill()  //  ()

哦对不起,它在我的字体中看起来一样。 我在问,如果 ..= 是一个复合词
赋值运算符如+=,它执行什么操作(对应
+)?

2017 年 2 月 22 日,星期三,晚上 8:29,刘俊峰通知@github.com
写道:

@durka https://github.com/durka ..= 看起来像赋值
运算符,用例必须很少见。 ~是潮不分。

impl 填充范围{
fn fill() -> String { ... }
}
为 RangeAssign 实现 FillAsign{
fn 填充(&mut self) { ... }
}
(String::new("abc") .. String::new("f")).fill() // "abcdef"
(String::new("abc") ..= String::new("f")).fill() // ()


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-281861478
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3n39uqbADB1rNtBh3PBTRY2XBXOUNks5rfOD-gaJpZM4F4LbW
.

@durka @nikomatsakis好吧,我希望这能尽快解决。 目前的情况很尴尬,改变语法也会如此。

@pornelmatch弃用...会破坏兼容性,因此这不是一个好的解决方案。 我仍然发现...是最合适的(不过它与 Ruby 完全相反,但 Rubyists 没有讨论过类似的问题)。

@hyst329...可能更容易出错,因为缺少或添加一个.将赋予新的含义

弃用不会破坏事物。 现有程序必须永远支持旧语法,但可以通过文档和 rustfmt 引导用户使用新语法。

但是可以通过文档和 rustfmt 引导用户使用新语法。

我强烈建议不要为此使用 rustfmt。 在“自动应用更改”模式下使用时,它会加剧...的枪式质量,因为它可以默默地将错别字转换为看起来更有目的的东西。 (从而使它们在以后的检查中更容易被忽视。)

“请检查您的意思并使用无法自动修复的....= ”的编译器警告将更符合现有的尽量减少人为错误的机会。

请注意,我是在模式中现有的...上下文中讨论的,其中不存在脚踏枪。 目前 Rust 处于暂时无枪的情况,其中模式只允许...和表达式只允许.. ,所以两者都是安全的,不会出现拼写错误。

当然,我不建议将表达式中的...转换..= ,因为这当然只会使拼写错误永久化。

啊。 我已经忘记了。 谢谢你的提醒。

@adelarsq实际上,例如'a'..'z'128u8..255u8类的常见错误可以很容易地作为警告集成到cargo-clippy中。 而且, .....的宽度明显不同(当然,当使用等宽字体时;不使用它通常对于编写源代码来说通常是一个坏主意——不仅是 Rust) .

我们可以将它的语法设为 (unicode 水平省略号)而不是...这样至少没有人会不小心输入它。

编辑:哦,没有人认真对待这个建议 :cry: 抱歉打扰了。

我不知道,上次我检查了 Google Docs 会自动将...转换为省略号。 文本编辑行业的主要参与者。

此外,并不是每个人都有一个Compose键来方便地输入Compose . 当他们确实想要

在 Windows 上,我可以使用Alt + 0133和小键盘输入省略号!

类似的基于代码点的机制存在于基于 X11 的桌面上的堆栈的各个层(我记得 GTK+ 和 X11 输入堆栈有自己的独立解决方案),但是按数字记住代码点是一个主要的麻烦。

Compose是一个 ṽèŕÿ 直观的解决方案。

我记得的唯一 Windows Alt序列是我小时候制作的所有 DOS 批处理文件菜单中的Alt + 219

当前的语法已经存在很长时间了,让我们已经稳定它并停止这种无休止的自行车棚。

保持当前的语法是我们能做的最糟糕的事情,因为它有很多真正的缺点。 这不仅仅是自行车棚 - 应该正确完成。 跳过整个线程,到目前为止, ..=语法得到了最多的接受......

在这一点上,我确实觉得它有点像在打败一匹死马,但是当您考虑它时... .....之间的区别实际上是您可能的最小字符的一个副本可以打字或阅读,与一组相同的字符混合在一起,并且有可能在完全无法区分的情况下创建一个非常常见且经常令人恼火地难以发现的错误类别(逐个错误)对人和机器。

或者我们可以使用世界上任何其他语法。

一方面我很欣赏这种担忧……另一方面,当前的...模式匹配语法已经包含在内,使其与 Rust 其他地方已经使用的语法完全一致。

我个人在识别差异方面没有任何问题,尽管我承认有视力问题的人,或者使用 4k 显示器和 10pt 字体的人可能会。

但似乎共识是在..= ,我想我也同意。

FWIW,我遇到过这样的情况,当我的意思是.. ...时,我不小心输入了.. ,然后有一段时间没有注意到,但过了一段时间我想知道为什么我的程序表现得很奇怪。
所以是的,应该有更明显的区别,而..=最有意义。

提名@rust-lang/lang 讨论。 我认为我们应该采用..=并收工。 我们需要修改后的 RFC 吗? 去做就对了? 这是否涉及弃用模式中现有的...语法? (我假设是这样。)

我强烈赞成不要将...用于范围。 我不知道它是否已在此线程或 RFC 线程中提及,但除了.....不合理地相似之外,我们可能还想使用...用于可变参数泛型,这比 IMO 包含的范围重要得多。

..=似乎很清楚,它的相对丑陋是因为它不如..常见。

这是否涉及弃用现有的 ... 模式语法? (我假设是这样。)

这似乎是个好主意。 警告...并尽可能支持....=模式。

我通常担心在没有自动工具更新语法的情况下引入会影响这么多人的警告,但是从.....=是一个特别简单的更改。 我们也可以弃用但推迟使其成为警告,直到我们拥有这样的工具。 其他人怎么看?

我强烈支持...因为它是更“常用”的语法; 我不知道任何使用..= ,但许多使用.....

如果反对..=情绪强烈,我宁愿不使用包含范围语法(而不是选择(a..b).inclusive()方法,这对我来说似乎足够简洁)以避免视觉问题并再次免费...用于可变参数泛型。

编辑:针对一个很好的理由(a..b).inclusive()的是,我们仍然有...match并没有新的语法来取代它,很遗憾。 :使困惑:

@steveklabnik道歉,如果这已经在这个(很长)线程中的某个地方提到过,但是:还有哪些其他语言分别将.....用于独占和包含范围?

Rust 有从其他语言中采用有用的特性和语法的历史,但有选择地,并在适当的时候拒绝或调整事物。

@joshtriplett Ruby 使用两者,但含义相反( ..是包含的, ...是不包含的)。 我认为在 Ruby 中这不是一个好主意,而且如果我们同时拥有两者似乎更可能令人困惑,但反过来。

@joshtriplett我最熟悉的是 Ruby; 我认为它是从 Perl 得到的,但我不完全确定。 相比于..=我对 Ruby 的语义倒退更满意。

老实说,我更喜欢稳定的包含范围语法而不是其他任何东西,并且认识到我对..=强烈不喜欢是个人的事情,有理智的人可能会不同意。

@steveklabnik Swift 使用..< ,我想,对吧? 这似乎与..=相似,但更糟糕的是,它针对(imo)错误的情况进行了优化。 =)

Swift 使用 ..< 表示独占和 ... 表示包含(它们的术语是
“半开”和“封闭”)。

我仍然喜欢 ..<(用 .. 作为速记)和 ..=.

但另一个悬而未决的问题(可能不在此跟踪问题的范围内)是我们是否“只是”采用封闭范围的语法,或者也采用第一点开放的范围的语法(syntaxen?),即稻草人 >..> 和>..=.

2017 年 3 月 16 日星期四下午 2:19,Niko Matsakis通知@github.com
写道:

@steveklabnik https://github.com/steveklabnik Swift 使用 ..<,我认为,
对? 这似乎类似于 ..= 但更糟糕的是,它优化了
(imo)错误的情况。 =)


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-287147321
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3n0Wop5fJh9HVo7pSqo0riHm96Gm4ks5rmX1BgaJpZM4F4LbW
.

我不介意在前奏中有一个inclusive函数:

for x in inclusive(1..10) {

}

我从来没有觉得匹配对称是一个令人信服的论点。 我想我们决定添加独有的..模式,但我也不喜欢那些 - 模式中的值现在与模式不匹配! 匹配范围与遍历范围根本不同,它们没有理由必须是对称的。 如果它仍然是一个选项,我会倾向于不允许..在模式中,但我认为它不是?

我觉得..=...的缺点都很明显 - ..=很奇怪,但是...增加了 1 个错误的可能性。

拥有一个看起来很奇怪的操作符比这种永无止境的错误潜力要好(每种语言都引入了其他人没有的操作符,例如 Swift 中的..< ,F# 和 Scala 中的所有操作)。 无论如何,人们将不得不阅读 Rust 的书。
考虑到很多人是从 Ruby 来到 Rust 的,我们不应该把它与 Ruby 相比。 (除了...将 off 的可能性增加 1 个错误的论点之外。)
你怎么可以接受的..<斯威夫特但不接受的..=鲁斯特? ..=并不奇怪。

在模式中扩展范围语法和 AFAIK 一样仍然是一个悬而未决的问题。
一方面,我们不能完全做到,因为Enum::Variant(..)已经
有效并将其更改为意味着Enum::Variant(RangeFull)将被破坏。

在星期四,2017年3月16日在下午3点07分,Boscop [email protected]写道:

最好有一个看起来很奇怪的运算符(每种语言都引入了
其他人没有的操作符,例如 ..< 在 Swift 中,在 F# 中的所有操作
和斯卡拉)。 无论如何,人们将不得不阅读 Rust 的书。
考虑到很多人是从 Ruby 来到 Rust 的,我们
与 Ruby 相比,它不应该倒退。 (除了论证
那……将 off 的可能性增加 1 个错误。)
你怎么能在 Swift 中接受 ..< 而在 Rust 中不接受 ..= ?


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-287160485
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3nz9ZNR2utl7LPTVvQPQ_Ma8sDBGuks5rmYhmgaJpZM4F4LbW
.

所以。 我希望能够输入诸如slice.get(10...30)类的东西并吃掉我的蛋糕。

我已经说服自己,与任何其他语法相比,我更喜欢inclusive(0..10)

  • 虽然@nagisa想要写slice.get(10...30) ,我希望有密切关注这是否是slice.get(10...30)slice.get(10..30) 。 我认为语法的接近性是一个真正的问题。
  • 我认为每个人都同意..=是不美观的,并且可能不直观。
  • (0..10).inclusive()是相同的语法,但不太方便。 从技术上讲, inclusive prelude 可能会支持这两种语法。

我认为它看起来像这样:

trait IntoInclusive {
    type Inclusive;
    fn inclusive(self) -> Self::Inclusive;
}

fn inclusive<T: IntoInclusive>(range: T) -> T::IntoInclusive {
    range.inclusive()
}

我认为每个人都同意 ..= 不美观,而且可能不直观。

我认为这样说有点过于概括了。 我发现..=比像inclusive()这样的方法更美观和直观。

(此外,我们不知道对..=的不喜欢有多少可能是潜意识(或有意识的)努力寻找不是...东西的问题。)

.inclusive()对于经常发生的事情来说太长了(关于这一点,我也认为.enumerate()应该有一个更短的形式)。
但即使我们有.inclusive() ,也应该只有一个函数,而不是两个。
此外,没有包含范围语法将不允许在match
但也许我们需要一种方法来以通用方式指定提取器,例如在Scala 中? 这样可以在匹配中使用任何类型,以便匹配将隐式调用其unapply方法。

(此外,我们不知道对 ..= 的不喜欢有多少可能是潜意识(或有意识的)努力寻找不是......的事情的问题。)

没有我。 这有点像恶意指控。

此外,没有包含范围语法将不允许它们在匹配中使用。

match已经支持包含范围模式。 事实上,它们是我们今天唯一支持作为模式的范围。

@withoutboats是的,但我说“没有包含范围的语法不允许它们在匹配中使用”。 现在有一个语法,但我的论点是反对.inclusive()因为它不能用于 match 除非我们有像 Scala 这样的提取器。 这个问题的重点是包含范围语法不应该是一种特殊情况,它只适用于匹配并确定语法应该是什么而不是当前的语法。

包括: for i in 1..10! { }

作为使用 Java/C/C++ 超过 15 年的人,我发现.....非常令人困惑,并且可能仅通过输入错误就可能导致错误。 此外,与 Ruby 的关系使这更加令人困惑。 这就是为什么..=或任何其他替代方案更好的原因。

把我的“帽子”扔进戒指:

for i in 1..10^

帽子/插入符号表示正确的值一直向上_向上_。

@leebenson我个人认为如果它在中间会更好,而不是固定在外面。

for i in 1..^10

@retep998我认为在我点击发送之后......实际上可能更好。

@retep998我喜欢你对..^建议,比..=好得多; 它似乎更能唤起它的含义,并且避免看起来像增强赋值运算符的奇怪变体(如+=*= )。 也就是说,任何一个都比...好得多。

我不能落后于..^

在个人层面上,我发现它非常丑陋(部分原因是.. ^在许多字体中与

作为 UI/UX 人员,我认为这是一个为了自己的利益而过于聪明的例子。

如果我从另一种语言进入并看到..^ ,我什5..^15可能是15! - 4!一些奇怪的部分阶乘简写

(如果我们不考虑上下文, ...可能意味着“回调被插入这里”或“发出事件”,类似于散文写作中对话中的“内容省略”的含义,只是为了展示最直接的例子。就它如何与新人的期望相互作用而言,通过它与箭头的相似性给它一个“一路向上”的意思就像通过手艺变魔术一样。)

相比之下, =有先例既指代赋值操作又指等式概念,并且没有“奇怪的求幂语法”之类的对..=误解,因为您可以得到最接近的“赋值运算符尚未处理的赋值 + 相等”是“与一系列数字有关,以右侧数字结尾”......这是对范围语法所做的模糊但适当的定义。

我还担心,即使我确实认识到..^在上下文中的使用是范围语法,但一开始我也无法直观地知道它是包含性的还是独占性的,因为^没有任何意义2..^8是一个从 2 开始的开放式范围的简写,并逐步将上一步推到 8 次方。(即2..Inf^8而不是2..+8是“以 8 为步长从 2 迭代到无穷大”的简写。)

..=也避免了这个问题,因为人们在编写while循环时习惯于以< (独占)与<= (包括)的方式进行思考和 C 风格的for循环。

@ssokolow合法分析。

就个人而言,我可以支持..=..^ 。 任何一个的符号系统对我来说都有意义 - 即分别是“高达和等于”或简单地“高达”。 在我看来,它们都是同一件事。

很难提出让每个人都满意的东西,因为我们都从其他语言中汲取了历史,随之而来的是受污染的符号系统/偏见。 例如,我最初添加了^符号_after_ 数字,例如,因为插入 before 有代表“步骤”或指数的感觉,而后缀使范围未受污染,并且感觉更纯粹。 但这只是我。

在任何情况下,我更喜欢某种形式的速记符号,而不是隐式地 +1 右侧 val 的函数调用。 我同意之前的评论,即这种语法太常见,无法委托给感觉像函数调用的东西。 我什至不介意... ,但是当然,这可能是新衣服中的= / ==错误并且一定会射中某人的脚......

很多人似乎很不喜欢..=没有人说任何负面的话
关于......它只是被悄悄地忽略了(除了几个竖起大拇指)我
以为我会再次提出并让人们考虑并给出
如果他们反对,则不使用它的原因。

我什至不想提及它,因为它只是更多的噪音,但是.:
(点冒号)是否包含? 它是 3 个点但 2 个字符,我认为
形状使其区别于..

2017 年 3 月 18 日星期六上午 11:50,Lee Benson通知@github.com
写道:

@ssokolow https://github.com/ssokolow合法分析。

就个人而言,我可以落后于 ..= 或 ..^。 两者的符号系统
对我来说很有意义 - 即“达到并等于”或简单地“达到”,
分别。 在我看来,它们都是同一件事。

很难想出让所有人都满意的东西,
因为我们都从其他语言中带来了历史,并因此受到了污染
符号/偏差。 我最初在数字添加了 ^ 符号,因为
例如,因为之前插入有代表“一步”的感觉
或指数,而后缀使范围不受污染,并且以某种方式更纯
感觉。 但这只是我。

无论如何,我更喜欢某种形式的速记符号而不是
隐式+1s 右侧val 的函数调用。 我之前同意
评论说这是一种太常见的语法,无法委托给某些东西
感觉就像一个函数调用。 我什至不介意......,但当然,这是
可能是新衣服中的 = / == 错误,并且一定会射中某人
脚...


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-287566556
或静音线程
https://github.com/notifications/unsubscribe-auth/AIhJ6jWgPwndKaQvVjULlV_OoC6WDO0Cks5rnCeLgaJpZM4F4LbW
.

哦,这还处于自行车棚阶段吗? 😆

回想一下,我想我同意@nikomatsakis 的观点,只是让它..=并收工。 .....的相似性太微妙了,我宁愿看到...令牌被毫无歧义地用于可变参数泛型 (https://github.com/ rust-lang/rfcs/pull/1935),它实现了一个非常独特的目的,应该减少两者之间的混淆。

我不确定是否仍然希望为所有半开放变体提供更通用的语法,但我认为不值得努力提供....=之外的语言语法.

我什至不想提及它,因为它只是更多的噪音,但是 .:(点冒号)是否包含在内?

我认为@ssokolow提出了一些很好的观点:UI/聪明。 我认为为了欺骗你的眼睛看到其他东西而改变第三个点的方向可能属于这一类。

我个人对第三个点有_零_反对意见,除了知道它最终会绊倒一些人。 但它也很容易解释,所以我不确定设计巧妙的解决方法的责任应该在语言上。 是 '2 点排他性; 包含 3 个点'真的 _that_ 难以掌握/调试吗?

无论如何 - 谁做出最终决定,关闭它的下一步是什么? 18 个月在讨论第三个角色可能_is_bikeshedding 在这一点上 😄

同意,^ 使它看起来像一个步骤。
IMO 与其他op=运算符的不一致是没有问题的,因为在a ..= b的意义上,我们不可能拥有a = a .. b ,因为..是不是运算符,而是构造 Range 的语法糖(我们没有通用的 op 重载方案,其中任何 op 都会自动获得op=.. )。
我不是说..=不看文档就很清楚。 但是一旦人们看了文档,就更容易记住,而且无论如何他们都必须看文档。

鉴于@nikomatsakis的提名,我想我们最终会在下周的 lang-team 会议上讨论它,并可能在那时打电话。 我同意这只是需要 lang 团队打个电话并结束自行车棚。

我还担心,即使我确实认识到..^在上下文中的使用是范围语法,我一开始也无法直观地知道它是包容性的还是排他性的

同意。 事实上,我已经在 Perl 6 中看到了这种语法,它的意思是独占,与这里的提议相反。

@solson这是一个非常有说服力的反对它的论点。

Perl 似乎具有完全通用的语法,其中 .. 含义包括(在两个
侧) 和 ^ 在任一侧使该绑定具有排他性。

2017 年 3 月 18 日星期六下午 6:51,Josh Triplett通知@ github.com
写道:

@solson https://github.com/solson这是一个非常有说服力的论点
反对。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-287580739
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3n7Fnn1_t9BkYOhfS-7oCaGlVff2aks5rnF_5gaJpZM4F4LbW
.

所以,我很抱歉地说,但是当我们在@rust-lang/lang 会议上讨论这个问题时,我们未能达成共识。 特别是@withoutboats有一些严重的保留意见,希望他们可以为自己播出。

我们讨论的一些要点:

  • 如果我们在表达式和模式中有包含范围的语法,它应该是相同的

    • 即,如果我们采用x ..= y ,这意味着弃用现有的x...y模式语法。

  • 一个诱人的选择是“什么都不做”,只写(x..y).inclusive()或类似的东西。 但是,这不适用于模式(大概会保留为x...y )。 这本身就提出了一些问题:

    • 我们还想要独占范围模式吗? 例如match 3 { 1..3 => false, .. }



      • 如果是这样,那么我们就有了同样的潜在困惑!



    • @withoutboats似乎认为我们可能不想要这样的模式。 我自己和@joshtriplett对此表示怀疑; 我想我们都认为它们是那种在你想要它们之前似乎无关紧要的东西,然后它们觉得绝对必要。 =)

  • 关于独占范围模式的另一个问题是与(同样不稳定的)切片模式交互不佳(有关详细信息,请参见 https://github.com/rust-lang/rust/issues/23121)。

我认为从这次讨论中得出的一件事是,最好立即就所有相互冲突的因素做出决定。 换句话说,通过一个决定:

  • 如何处理独占范围表达式
  • 我们是否必须弃用/更改现有的独占范围模式
  • 如何处理包含范围模式
  • 如何处理切片模式

在我开始写这篇文章之前,我想说我感到非常不确定,在谈话的每一刻,我们实际上都在谈论同一个概念。 例如,Niko 说“直到你想要它们之前,独占范围模式似乎无关紧要”,但我认为 Niko 和 Josh 当时正在谈论包含范围表达。

(我认为在 Niko 帖子的最后一部分,当前读取“独占范围表达式”的第一个项目符号应该说“包含范围表达式”。)

TL; DR 我的意见

关于范围表达式:

  • 我们不应该为包含范围表达式引入任何语法——既不是...也不是..=
  • 我们应该在前奏中添加一个函数,该函数接受一个不包括的范围值并返回一个包含的范围值。 所以你应该写inclusive(0..10) (这个名字可以是bikeshedded)。

关于范围模式:

  • 我们不应该引入排他性范围模式,或以任何方式创建一个范围模式。

换句话说,我们应该做的唯一实质性更改是库更改:在前奏中添加一个函数。

范围表达式

我的论点的基础是这样一个事实,即迭代包含范围值是一种不常见的需求。 我认为尽管 RFC 在 18 个月前被接受,但我们仍然没有稳定这个功能 - 不是因为实现问题,而是因为我们对折衷不满意,我认为这证明了这一点。

我认为经常需要包含范围表达式,我们应该支持创建它们的直接方式,但还不够频繁,以至于它们克服了我们迄今为止讨论过的语法的任何缺点。

特别是,每个句法解决方案都有一个缺点,即它们都不是真正的自文档化。 0...100..=10是一个包含范围表达式是相对不明显的。 由于它们会相对较少地遇到,因此对于第一次遇到它们的用户来说,这将是一个绊脚石。

也就是说,如果用户甚至注意到他们没有处理“正常”的..范围。 当然,这是...的大问题,但..=并没有完全消除这个问题。 在浏览代码时,很容易错过那个=字符(或^:或其他任何字符)。 不像额外的.那么容易,但我不相信它足够引人注目。

我实际上认为.....=之间存在“显着性与明显性”的权衡。 我认为...的含义比..=更明显(除非您来自 Ruby,这两种语法具有相反的含义),但它绝对不那么引人注目

但我认为像inclusive(0..10)这样的前奏函数比我们讨论过的任何语法都更明显也更引人注目。 是的,它需要输入更多字符,但该属性的缺点与使用频率有关。

它还回避了任何解析和标记问题,并帮助用户解决(非常烦人的)范围与方法优先级问题,这要求他们编写(0..10).filter等。

范围模式

我认为我们不应该添加..主要原因是它在切片模式周围引入了歧义,我认为这很有用。 我想通过不必解决它来解决这个问题。

第二个原因是我认为他们的风格很糟糕(我知道其他人不同意)。 例如:

if let 1..10 = x { .. }

我认为这令人困惑,因为10与包含它的模式不匹配。 Niko 提到这与不产生10独占范围表达式并没有真正不同,但我认为最大的区别在于我们有大量的 Dijsktra 风格的历史先例(和用例)来支持独占范围。 进入 Rust,我希望迭代和切片范围是排他性的,但我对模式没有那种期望。

它还具有表达式中.. / ...的“一对一”问题。

我知道 Niko 提到他想写:

match x {
    0..10 => { ... }
    10..20 => { ... }
}

但我真的非常希望看到:

match x {
    0...9 => { ... }
    10...19 => { .. }
}

无论如何,我很惊讶 Niko 的意思是他有时会发现这些“绝对必要”,所以我想听到更多的反驳。 由于它们必须是 constexpr,因此对我来说,它更像是“很高兴拥有”而不是“绝对必要”的东西。

我绝对觉得比包含范围表达式更容易影响专有范围模式。

一致性论证

Niko 提到在表达式和模式中同时使用.....对他来说很重要,因为它保持一致性。 我基本上对这个论点完全不为所动。 遍历范围和匹配范围并不是真正的类似操作,我们对待它们的方式存在差异是有道理的。

事实上,甚至没有一个实现 connect: 1..10产生一个 Range 值,而1...10匹配一个整数值。 它不像我们大多数对称表达式/模式语法那样具有结构化/解构连接。

将模式称为“领域模式”似乎在技术上比“范围模式”更正确🤓,这突出了非相似性。

@没有船

例如,Niko 说“直到你想要它们之前,独占范围模式似乎无关紧要”,但我认为 Niko 和 Josh 当时正在谈论包含范围表达。

就我而言,我发现在不同时间都需要独占和包含范围(尽管我在这两种情况下都使用了独占来处理稳定的 Rust,并且不得不在上部使用+1解决它边界)。 我想让它们可用于模式和表达式。

也就是说,就我个人而言,我不反对将函数用于包含范围,除了我确实希望有一种方法可以在patterns 中同时编写包含和排除范围,并且我希望这两种语法看起来不会混淆相似就像.....一样。 并给出了在模式中编写此类范围的语法,我不知道在表达式中为此类范围使用不同的语法是否有意义。

特别是,每个句法解决方案都有一个缺点,即它们都不是真正的自文档化。 相对不明显的是 0...10 或 0..=10 是包含范围表达式。 由于它们会相对较少地遇到,因此对于第一次遇到它们的用户来说,这将是一个绊脚石。

我同意这一点。 这种情况很少出现,我不反对不太紧凑的语法。 但是,我希望有一些机制可以在表达式和模式中编写包含和不包含的范围。

例如,我不介意编写包含范围的模式是否需要宏或类似的。

@joshtriplett这就是我想说的很清楚的地方,当你这样说时:

我发现在不同时间都需要独占和包含范围(尽管我在这两种情况下都使用了独占来处理稳定的 Rust,并且不得不在上限中使用 +1 来解决它)。

很明显你在谈论表达式,但你引用的部分是关于模式的(我知道你在下一段谈论模式,但我问的是该段没有解决的“必要性”问题😃) .

模式的现状是我们只支持包含范围模式,形式x...y 。 如果/何时发现独家范围模式真的令人沮丧,你能谈谈吗?

@没有船

如果/何时您发现独家范围模式真的令人沮丧,您能谈谈吗?

就像是

    match offset {
        0x0200 .. 0x0280 => { /* GICD_ISPENDR<n> */ }
        0x0280 .. 0x0300 => { /* GICD_ICPENDR<n> */ }
        0x0300 .. 0x0380 => { /* GICD_ISACTIVER<n> */ }
        0x0380 .. 0x0400 => { /* GICD_ICACTIVER<n> */ }
        0x0400 .. 0x0800 => { /* GICD_IPRIORITYR<n> */ }
    }

对比

    match offset {
        0x0200 ... 0x027C => { /* GICD_ISPENDR<n> */ }
        0x0280 ... 0x02FC => { /* GICD_ICPENDR<n> */ }
        0x0300 ... 0x037C => { /* GICD_ISACTIVER<n> */ }
        0x0380 ... 0x03FC => { /* GICD_ICACTIVER<n> */ }
        0x0400 ... 0x07FC => { /* GICD_IPRIORITYR<n> */ }
    }

我不会说这特别令人沮丧,但第一个肯定看起来更好。

@withoutboats为清楚起见,我曾多次想要独占范围表达式、包含范围表达式和包含范围模式。 我无法立即想到我非常关心拥有专属范围模式的时间,尽管我也不反对它们。 但即使我们没有独占范围模式,如果包含范围模式使用...而独占范围表达式使用.. ,我仍然会感到非常困惑。

@petrochenkov我认为那些应该以F结尾,而不是C

我遇到了与十六进制范围模式相同的情况,例如0x8000...0x9FFF => /* body */ 。 我发现0x8000..0xA000具有更直观的属性,例如无需考虑它我立即看到范围的大小为0xA000 - 0x8000 = 0x2000并且下一个相邻范围从0xA000

处理在包含范围内查看这些事实所需的+1是一个我可以接受的小差异,但独家范围(模式和表达式)通常更适合我的工作。

@petrochenkov我可以

但是,我们将如何处理切片语法的歧义?

@joshtriplett

如果包含范围模式使用...而排他范围表达式使用..我仍然会感到非常困惑。

这就是 Rust 今天的工作方式,它似乎不是一个重要的混乱来源?

@索尔森

我认为那些应该以 F 结尾,而不是以 C 结尾?

不 :)
(这些东西是 32 位的,而offset是四的倍数。)

@没有船

我可以理解为什么您更喜欢十六进制数字的独占范围(我仍然可能不会,但这感觉就像一个非常YMMV的交易)。

我应该注意,这不是一个强烈的偏好,我仍然可以同时删除独占模式和包含范围(但不是其中之一,那太荒谬了)。

但是,我们将如何处理切片语法的歧义?

容易地! PATTERN.. => .. @ PATTERN

我希望包含范围简单的主要原因是我不止一次遇到过在变量中传递停止值的情况,而这正是一种变量类型可以容纳的最大值,因此唯一的解决方案在编译时排除溢出是:

  1. 使用包含范围(最干净,但不稳定)
  2. + 1之前向上转换(假设我还没有使用u64并且不雅)
  3. 取值中的较小者和范围内的最大值减一,然后在适当的情况下再运行一次任务。

养成使用包含范围的习惯,而不是将+ 1到没有固有目的的算法中,这是防止稍后在cargo fuzz再次遇到它们的重要方法......并使用名称中包含比+ 1更多字符的“make inclusive from exclusive”函数给人的印象是包含范围是一种特殊的东西,而不是您应该习惯性使用的东西。

这是我反对它的最大原因之一。 它传达了一种印象,即包含范围是一种黑客,在证明独占范围失败时使用。

@ssokolow但该用例已被前奏函数轻松覆盖。 没有人认为应该不可能创建包含范围,只是他们是否应该使用语法糖来创建它们。

我喜欢@withoutboats的前奏功能想法。 我认为包含范围可能更常见的另一个地方是当您不使用整数时,例如,通过在 btree(或类似数据结构)上指定搜索范围。

@withoutboats我在你回复时对我的帖子进行了一些编辑,但我添加的要点是,在语法上使包容性范围成为二等公民(语法比将+ 1到专属范围要长),感觉像是对使用它们的一种微妙的劝阻和一种可能的“我稍后会在cargo fuzz见到你”的footgun。

如果不出意外,那就是可教性疣。

Rust 不是 Python 3.x,它具有无限的整数支持。 Rust 不会向用户隐藏硬件权衡,我认为..=我更喜欢作为使用u32和朋友而不是int 。 (特别是考虑到溢出/下溢错误是迄今为止cargo fuzz的“奖杯案例”中最常见的事情。)

编辑:请忽略您只在电子邮件通知中看到的任何位。 我刚醒来,我还没有开所有气瓶。

我根本不认为inclusive(n..m)是一种气馁......我更愿意写它,因为它是一个非常清晰的结构,使我的代码比n..(m + 1)n..=m更易于阅读

n..=m比 IMO 的inclusive(n..m)更像是一个可教性疣。

我认为对于匹配,希望完全覆盖数字范围,而不是特定类型的模式。

大概如果有“从以前的继续”语法,它也可以解决问题。

顺便说一句,由于只有第一个模式匹配,因此通常可以省略起始编号:

    match offset {
        0 ... 0x01FF => {}
        0 ... 0x027C => { /* GICD_ISPENDR<n> */ }
        0 ... 0x02FC => { /* GICD_ICPENDR<n> */ }
        0 ... 0x037C => { /* GICD_ISACTIVER<n> */ }
        0 ... 0x03FC => { /* GICD_ICACTIVER<n> */ }
        0 ... 0x07FC => { /* GICD_IPRIORITYR<n> */ }
    }

我承认这可能是一个视角问题,但是:

  1. 当我看到....= ,我想“嗯。我想知道为什么他们有两种语法来区分这么小的差异”,然后我会去寻找可以专注于的文档" 1..pivotpivot..end " 与 " x..=y其中y可能是最大可能值"。

  2. 在我有足够的经验来习惯性地考虑可变大小之前,我只是使用了+ 1不是inclusive() (如果我什至去寻找它),因为我一直在使用+ 1从小学开始,它很短而且很容易打字,而且我这个没有经验的自己习惯于使用 Python 和 JavaScript 等语言,在这些语言中,人们不会担心加法导致溢出。

编辑: ...这是我认为我们应该关注的第 1 点中的概念区别。 (即“从 X 到枢轴”和“从 X 到结束”在程序员的脑海中应该是不同的。)

@pornel
这太可怕了😄
在这种特定情况下,范围开始对于阅读代码的人来说真的非常重要,比任何包含/排除范围问题都重要得多。

@ssokolow在我看来,使+1成为问题的原因不是字符数,而是您必须处理溢出的可能性。 此外,它也不传达意图,并且需要争论优先级。 这些似乎都比字符数重要得多。

确实有人不知道溢出可能会在创建包含范围之前达到+1 ,但这似乎不依赖于语法。 两者都发现..=是一个东西,而inclusive()是一个东西,这都提供了可教的时刻,用于了解您为什么特别想要包含范围。

@彼得罗琴科夫

我仍然可以同时删除独占模式和包含范围(但不是其中之一,那太荒谬了)

你能解释一下为什么你对此如此强烈吗? 我绝对认为接受独占模式有一个缺点,因为它可能会导致用户期望0...10作为表达式,但对我来说似乎并没有那么糟糕

我对inclusive()部分问题是它“只是”一个函数,我担心人们会做一些事情,比如去 Rust 语法索引,搜索“范围”或“迭代器”,然后假设投资回报率不足对于“参见[ing] 迭代器”。

(“我不想在偶然发现有用的东西时阅读教科书......我只想在一个范围内迭代并重新取得进展。”)

@withoutboats如果我们有 inclusive(a..b),但我们不能在比赛中使用它,那么 IMO 不值得。
大多数情况下,当我使用包含范围时,它处于匹配模式中!
那么为什么我们不能删除...而只是在 match 内部和外部使用..=呢?

@Boscop的提议不是在匹配中删除... ,而是让模式完全保持稳定状态。

@ssokolow似乎可以通过..部分中的注释轻松解决

@withoutboats但是为什么不在匹配中删除...并使用..=代替,这样它是一致的?
(这样它在比赛内外都是..=

对于浮点数的数字范围覆盖,独家帮助。 例如,这些边界之一被完全覆盖,但另一个没有:

match x {
    0.0...3.141592653589792 => 1,
    3.141592653589793...6.283185307179585 => 2,
    6.283185307179586...10.0 => 3,
    _ => 4,
}

并且用重叠来写它反而让人觉得恶心(在道德上类似于上面的“因为手臂是有序的,所以从 -∞ 开始一切”)。 另请参阅日期时间,例如 ISO8601 如何允许 T24:00,因为一天是 [00:00, 24:00),而不是 [00:00, 23:59:59]。 或字符串,或有理数,或...

如果可以选择仅排他性或仅包容性,我每次都会选择排他性。

(旁白:用于索引的1 <= x <= N模式实际上最好作为0 < x <= N ,这也是排他性的——尽管半封闭而不是半开放——出于同样的原因 Dijkstra 说,只是切换为基于 1 的索引而不是基于 0 的索引。)

这个操作符对我在这里提出的钳位函数非常有帮助: https :

0.0..1.0+EPSILON

我什至不确定这是否正确,但现在很难声明一个包含范围的浮点数。

正确的方法是使用nextafter ,而不是 epsilon。 即x...y == x..nextafter(y) 。 ieee754 crate 公开了这样的功能

哎呀,我对inclusive(a..b)语法发表了评论,但我意识到这不是真的。 无论如何,我喜欢它,但我希望我们可以用自行车命名一个更好的名字。

@durka这个名字对我来说似乎很清楚。 你能详细说明你对它的担忧吗?

因此,对于包含范围,我们将在matchinclusive(a..b)之外的匹配中有a ... b
为什么我们不能保持一致并且到处都有a ..= b

是否有任何因素阻止ops::{RangeInclusive, RangeToInclusive}正式稳定下来?

现在似乎主要的障碍是关于语法的辩论,尽管不管辩论如何,我很确定无论最终语法是什么,包含的范围都会存在。

为稳定库实现这些类型会很好,然后这些库的使用者可以决定启用功能标志,如果他们想使用特殊语法。

前几天我注意到关于RangeInclusive的一件事:如果你试图接受一个范围,那么编码就会很痛苦。 钳位线程正在谈论允许.clamp(1...9) ,但代码最终看起来像这样:

    fn clamp(self, r: RangeInclusive<Self>) -> Self where Self : Sized {
        match r {
            RangeInclusive::Empty { .. } =>
                panic!("Cannot clamp to an empty range"),
            RangeInclusive::NonEmpty { start, end } => {
                assert!(start <= end, "Cannot clamp to a degenerate range");
                if self < start { start }
                else if self > end { end }
                else { self }
            }
        }
    }

需要处理RangeInclusive::Empty感觉没有必要,因为目标只是接受具有良好语法的对。 如果它不是枚举,它可能只是fn clamp(self, RangeInclusive { start, end }: RangeInclusive<Self>) ,并且更干净。

不幸的是,我对如何处理它没有一个好的答案,因为要求 .into_iter() 包含但不排斥也是不幸的......

随机想法:看到...模式语法如何与包含范围类型并没有真正相关,我们可能会考虑弃用它的语法,以支持与此处提出的...无关的语法。

由于包含范围模式与|模式更密切相关,因此|...可能是一个很好的候选者:

match {
    1 | 2 | 3 => ...
    1 |... 3  => ...
}

最终结果将是包含和排除范围语法与模式匹配不再是 1:1 的关系,因此不需要与其保持一致。

@scottmcm

不幸的是,我对如何处理它没有一个好的答案,因为要求 .into_iter() 包含但不排斥也是不幸的......

也许我们可以添加一个像range.nonempty()这样的助手,它会为空范围恐慌,并返回一对?

或者,我们可以为RangeInclusive实现IntoIterator RangeInclusive并且它不会离恕我直言太远。

RangeInclusive::Empty 服务于什么用例? 为什么包含范围需要表示空范围的能力? 你会怎么写一个? (请注意,您已经可以编写诸如“范围从 5 到 4,包括在内”之类的内容,迭代可能会将其视为空。)

@joshtriplett主要情况是溢出,尽管有解决该问题的方法。

@joshtriplett start > end在一个重要情况下实际上不能代表空的包含范围: 0u8...255u8 。 当您到达255u8...255u8并尝试使用.next()时,您可能会感到恐慌或换行到0u8...255u8 ,它不为空。 因此,我们此时切换到Empty变体。

@solson啊,我明白了。 是的,这很痛苦,而且它包含范围的最大用例之一。

(我假设您的意思是所有这些情况下的255u8 。)

(我假设您在所有这些情况下的意思是 255u8。)

是的,谢谢。 已编辑。

@solson但是,在这种情况下可以通过交换 0 和 255 来纠正这种情况

@clarcharr是的。 由于.next()总是必须对Empty范围的生成进行特殊处理,因此它总是可以生成一个将被视为空的范围。

我个人更喜欢这种方式,因为它不涉及空范围。

所以这个话题已经持续了一年半。 我刚刚通读了所有内容,并想为新人发布一个简明的回顾,并希望能帮助我们做出决定:

Rust Stable 今天做了什么:

0..5表示半开区间,[0, 1, 2, 3, 4] 不能用于模式匹配
0...5代表一个封闭的区间[0, 1, 2, 3, 4, 5],只能用于模式匹配。

已经为可以在模式匹配之外使用的附加封闭范围语法提出了几种形式。 我将介绍每一个以及它们的优点和缺点。

0...5

优点:与现有的模式匹配语法一致,假设没有对模式匹配语法进行任何更改,则使语言感觉更具凝聚力。

缺点:容易打错字并因一个错误而导致错误,也容易由于其他语言使用此运算符来传达不同的概念而导致误解意图。

0..=5

优点:更难打错,语义更清晰

缺点:与现有的模式匹配语法不一致。 可能会引起用户问:为什么是...这里但是..=这里?

0..^5

..=非常相似,但有一个额外的缺点,因为它看起来像一个幂运算符。

inclusive(0..5)

优点:语义非常清晰。 不会打错字。

缺点:有点长。 也与模式匹配语法不一致。

0....5

优点:也避免了...

缺点:语义差,不符合模式匹配语法,类似模式匹配语法。

[0..5]无法使用。 方括号在语言中已经具有句法意义。

0..<=5无法使用。 与将值与范围进行比较的现有语法有冲突。

如果我们要更改模式匹配语法,则列出的每个具有“与模式匹配语法不一致”缺点的选项都可以改进,但该路由具有向后兼容性问题。 或者,我们也可以在模式匹配中使...和(在此处选择您的语法)等效,以避免破坏向后兼容性,但防止在模式匹配之外使用... 。 也许我们也可以更新样式指南,以阻止在模式匹配中使用... ,如果我们要走这条路的话。

也有一些关于创建更通用的范围语法的讨论,该语法允许您使上限和下限包含或排除,但我们可能甚至不需要该语法,因为半开和封闭范围可能覆盖99.9999% 的用例。

我试图尽可能地代表这个讨论。 如果您觉得我没有充分表达您的观点,请告诉我,以便我更新。

@Xeroxe感谢您的出色总结。

也许有一个工具(可能是 rustfmt 的插件)可以在决定时自动将模式匹配中使用...源转换为新语法(例如..= )。
这样我们就不会被“所有以旧方式编写的代码”所阻碍。
但是它必须被项目作者有意调用,并且应该在所有 Rust 媒体上都有一个通知/标题,以便每个人都知道这个变化。
有了这些,我认为将模式匹配中的...语法更改为新语法是没有问题的。

我认为我们可以在语法问题上做的一件事就是稳定 RangeInclusive,正如@clarcharr建议的那样。 这至少会解除人们的封锁。

我们还可以添加inclusive函数(或者只是添加到std::range或者也可能添加到序曲中); 这并不排除某一天拥有一流的语法,但它使现在构造 RangeInclusive 变得更加方便。

然而,所有这些似乎都是 libs 的决定,所以我不知道 lang 团队是否有权决定稳定/添加这些项目😅。

我个人更愿意将RangeInclusive本身转换为没有Empty变体的东西,然后让IntoIter具有变体。 考虑到在没有手动Empty { at }情况下构建空范围基本上是不可能的,这对我来说更有意义。

或者,在我提到的一个边缘情况下交换MAXMIN 。 这使得编写涉及RangeInclusive更通用代码变得更加困难,但这似乎是解决问题的合理方法。

不管发生什么,我都非常支持稳定标准库中的类型,无论语法问题如何,它都会存在。 它允许库编写稳定的代码,允许使用包含范围进行切片,以便在语法稳定时,人们已经实现了使用这些类型的代码。 出于某种原因,语法和类型位于不同的功能标志下。

@scottmcm我同意这可能应该是一个单独的线程。

为了继续推进语法讨论,我将提供我更愿意采取的路线。

我最喜欢..=语法,所以我觉得我们应该添加这个语法糖作为模式匹配中的...和模式匹配之外的 InclusiveRange。 然后为了保持语言的一致性,我们应该尝试将用户及其代码迁移到模式中的..=语法,使用公告和自动化工具。 一旦我们觉得我们已经从...迁移了足够多的用户,我们就可以使用编译器警告,然后最终(可能甚至几年后)编译器错误。

我的提案提交已经24天了,还没有任何评论。 我们应该推进那个计划吗?

编辑:在移动设备上我没有看到反对意见,所以我没有意识到存在不同意见。

@Xeroxe我不这么认为。 我不同意弃用...而支持..=是一个不错的选择,原因我已经在此线程中发布过。 我没有回复你的具体建议,因为同样的想法已经被提出和讨论过。 这里唯一清楚的是我们没有达成共识。 我想我们中的许多人都对讨论感到疲倦。

编辑:更具体地说,我不想弃用...而支持..=因为:

  • 弃用语法会造成巨大的流失成本; 即使我明确地喜欢..=我也不认为仅仅为了获得稳定的包含范围表达式而进行弃用周期是值得的。
  • 喜欢..= ,我认为它不明显且不清楚; 它的优势在于它不太可能因一个错误而导致关闭,但这并不意味着第一次看到它的用户会知道他们在看什么。
  • 我不同意这里模式和表达式之间需要对称的前提,因为它们不执行任何类似的结构化/解构操作。

(我在此评论期间改变了一些观点,我决定将其全部保留,以便其他人可以看到我的思考过程以及我得出的结论的原因)

由于我缺乏此类方面的经验,我无法真正评论弃用的成本。 但是我仍然支持..=

我认为在某个时候,我们必须愿意让用户学习一些东西。 编程作为一个整体是需要学习的,一般来说专门的语法总是以语义为代价。 我不希望人们第一眼就能认出语法, ..在这方面同样糟糕。

然而,过多的专业语法会导致语言看起来比我们想要的 Rust 更接近脑残。 所以我们必须小心,我们选择变成特殊语法的情况实际上足够常见,值得。 老实说,既然我已经输入了这个,我并不完全确定这个案例是否值得。 对包含范围的需求不足以保证语法。

然而,这种不一致仍然困扰着我。 在模式匹配中拥有包含函数和...感觉就像在英语中同时拥有灰色和灰色。 当我们有机会标准化时,我的一部分感觉我们应该这样做。 但是,在进行这种更改时也存在实际的后勤问题。 如果我们要设计 Rust 2.0(这可能很疯狂,我不知道)也许我们应该重新审视这个,但我想现在同时拥有灰色和灰色已经足够了。

我是支持使用的inclusive的情况下,模式匹配外的功能和...模式匹配在这个时候。

@没有船

  1. 如果你从不反对任何东西,你最终会得到所有(或多或少)像 C++ 这样的错误决定的联合。 这迫使新手学习更多,因为事情并不像他们本来的那样一致。
    所以有时弃用一些东西来为更好的解决方案让路是有意义的。

  2. 这并不意味着第一次看到它的用户会知道他们在看什么。

任何语法都是这种情况。 我们(了解 Rust 的人)有这种偏见,因为对我们来说,Rust 代码看起来很明显,但任何从另一种语言来到 Rust 的人都必须经常查找语法。 如果我们对包含范围使用..=...或任何其他语法,它不会改变,因为例如其他语言使用...作为独占范围,所以无论如何他们都必须查找它.
我们的目标不应该只是引入明显的特征:
如果我们只想拥有看起来很明显的功能,我们就无法拥有 Rust 中的大部分现有功能。 新手在文档看,无论如何,什么是错的看法? 医生很好!


  1. 如果您关心最小化新手必须查看文档的时间,我们应该努力在包含范围的构建和匹配之间实现对称! (和其他结构)

正如@withoutboats所说,我想我们很多人都厌倦了这个讨论; 我已经坐了一段时间了。 也就是说,我花了一些时间重新阅读(感谢@Xeroxe 的总结!)并在这里重新审视我的想法。

IMO,目前最重要的问题是我们提供的语法组合不完整...用于模式, ..用于表达式。 这对语法强烈地使您期望..可以在模式中工作,而...在表达式中 - 而它们却没有。 我相信从长远来看,这不是一个站得住脚的设计,真的很想修复它。

我还认为,鉴于我们已经为这两种范围提供了语法,最好继续这样做。 这给我们留下了几个选择:

  • 稳定表达式中的...并将..到模式中。 这是最不痛苦的变化,但围绕一对一错误的缺点进行了充分讨论。 尽管如此,其他语言也有这种组合,据我所知,并没有遭受此类错误的严重影响。

  • 弃用模式和表达式中的... ,将..=添加到两者中,并将..到模式。 解决了上述缺点,更痛苦(因为弃用),并为未来其他类型的范围(如左独占)打开了大门。

在这一点上,我主要是重新讨论,老实说,我认为此时没有更多要说的了。 我认为我们已经暴露了权衡,只需要 lang 团队进行评估并做出决定。 但我的评论的主旨是最初的观点,关于为什么我认为这里需要改变一些东西(以及为什么仅仅添加inclusive是不够的,IMO)。

尽管如此,其他语言也有这种组合,据我所知,并没有遭受此类错误的严重影响。

我担心这里的选择偏差。 我们没有可靠的方法来判断问题是小问题还是很少引起我们的注意。

此外,使用...感觉与 Rust 的设计理念和新兴最佳实践的“除非权衡过于严重,否则避免使用footguns”方面背道而驰。 (例如,建议创建新的enum类型而不是使用bool这样就更难混淆你的函数参数。)

例如,C 已经证明了if语句中的赋值在语言没有while let情况下很有用,但是人们已经认识到,当您的意思是==时键入= ==足以让 Python 之类的语言拒绝使用它,即使存在唯一替代品一反常态丑陋的情况。

反过来说,大约一周前,当我编码累了时,我实际上让 Clippy 发现了这样的案例......

foo == bar;  // This should be `foo = bar;`

......这似乎是我们在这里担心的那种“多次按下键”错误的完美例子......而且,与“ ==没有效果”不同,有对于.....进行 lint 没有好的方法。

@ssokolow说清楚,我对..=也很好; 我不认为弃用会如此痛苦,这是一个非常简单的自动修复。 大多数情况下,我只想解决这个问题。

我可能可以忍受稳定.. / ... (已经在每晚实施)。 我同意@aturon 的观点,即现有的语言表明这会起作用。

正如我所说,当 rust-lang/rfcs#1980 通过时,我真的很想稳定 libstd 类型,而无需进行语法讨论。

除了@aturon指出的内容之外,也许合并此和独占范围语法的跟踪问题会很有用? 也许为类型创建一个单独的跟踪问题,并在语法之前使用它来稳定类型。

我重新提名 lang 团队讨论。 我认为此时不太可能出现重大的新想法或权衡。 我们需要就已经做出的权衡做出决定。

在2017年5月18日上午09时55分30秒PDT,亚伦Turon [email protected]写道:

我重新提名 lang 团队讨论。 我认为这是非常不可能的
新的想法或权衡将在此时出现
观点。 我们需要就已经做出的权衡做出决定
布置。

由于会议,我将出去参加下周的会议。 如果在下周的会议上讨论这个问题,我将表达我对...以外的任何解决方案的支持,无论是..=inclusive还是其他。

在我们讨论休息/传播语法时,这是值得的。
我投票..为独家范围, ...为包容性, ....为休息/传播。

take_range(..max); // exclusive range
take_range(...max); // inclusive range
take_multiple_args(....tuple); // spread
if let 0..10 = get_num() {} // exclusive range pattern
if let 0...9 = get_num() {} // inclusive range pattern
if let [first, ....rest] = get_slice() {} // rest pattern

我会为休息片投...票有两个原因:

  1. 人们可能已经熟悉了...意思,比如 CoffeeScript(CoffeeScript 在可变参数的函数签名中使用rest...并将它们称为“splats”)和英语(使用正确的 Unicode代码点与否,它是三个看起来像省略号的句点,而不是四个,人们在理解省略号方面做得很好,大致意思是英语中的“还有更多,但我们不会大声说出来”,纯粹是因为遇到它正在使用。)

  2. 除非我遗漏了一些关于 Rust 语法的信息,否则使用....=作为范围而...用于其余切片意味着,在任何情况下,输入...当你的意思是..或反之亦然仍然是一个编译时错误。

    为此,我基于两个假设进行操作:

    1. 单独使用 rest 语法(在序列解包上下文之外)将被禁止作为容易打错字的无操作。 (即,如果允许, for _ in ...rest将与for _ in rest相同,但几乎可以肯定是一个错字。

    2. 使用开放式范围作为要分配的模式是无效的。 (即let [first, ..rest] =将无效。)

@ssokolow三点已经表示模式中的一个范围,因此将其更改为休息语法将是一个重大变化。

@phaux点。 出于某种原因,我忘记了这一点。

也许可以挂起“如果我们制作 Rust 2.0”标签。

三点已经表示模式中的一个范围,因此将其更改为休息语法将是一个重大变化。

但是,模式中的...必须在两侧都有表达式,我相信( a...b ),而其余语法使用...作为前缀,不是吗?

lang 团队在今天的会议上再次讨论了这个特性,大致得出了以下矩阵:

  • 仅支持模式中的...和表达式中的..是站不住脚的设计; 它导致用户期望语法可以正常工作。

  • 在这两个地方都允许.....会有所帮助,但一对一的问题是一个真正的问题; 我们没有人急于收到有关人们花费数小时来追踪错误时期的报告。

  • 移动到..=..不太美观,但避免了上面非常实际的实际问题。 我们也可以以非常温和的方式推出它:首先引入..=作为替代语法(rustfmt 可以重写),只有在它变得惯用之后,才弃用...

如果您不知道,团队认为..=..是我们前进的最佳途径。 这个问题也被讨论到了不太可能提出新论点的程度,所以我们准备冒险:我们正在寻找愿意为两者实现..=符号的人模式和表达式,然后我们将去 FCP!

为此,我们正在寻找某人(或某些人)来推动实施。 可能这可以在一些较小的 PR 中完成:

  • 首先,让我们将..=到解析器作为...的别名并转换现有测试。

    • ...应该继续工作,当然,我们希望这是一个“无声的”弃用,所以不需要发出警告等(还)。

    • 因此,我们需要保持对...模式的测试

    • 我认为这样做的方法可能是通过添加DotDotEquals标记(这里是现有的DotDotDot )来修改词法分析器,然后修改解析器以在我们的任何地方接受DotDotEquals现在接受DotDotDot示例

    • ripgrep DotDotDot是你的朋友;)

  • 表达式中的...从来都不是稳定的,所以我们可以把它改成..=并终止旧的支持

    • 为了对野外的人友善,我们可能会经历一个弃用期,但我不确定这是必要的(想法?)

需要注意的是,在实现时,语法extern fn foo(a: u32, ...)不应更改为..= 😆

很想接受它,因为它看起来是进入代码的第一步,但我在接下来的 2 周内不会有太多时间,所以如果有人想拿起它,请随意!

我个人更喜欢..^不是..= ,因为a operator= b已经是一些运营商的别名a = a operator b 。 另一方面, ^的使用要少得多,仅用于 XOR,因此应该不会引起混淆。

..产生的类型与其左操作数和右操作数的类型不同,所以我不认为这是..= 。 上下文还有助于识别运算符的用途,例如+=返回()以便它可以作为自己的语句出现,通常在自己的行上。 而..=返回 InclusiveRange,因此它将在其他指令中显示为表达式。 此外,如上所述..^看起来与取幂有关而不是范围。

@Xaeroxe ^在 Rust 中与求幂无关(尽管它在其他语言中也是如此),而+=-=*=全部存在于 Rust 中。 事实上,甚至^=存在。

但是 idk,也有..=也很好。

既然#42134 被合并了,我们现在可以移动以稳定库结构吗? 我认为在稳定之前我们将要等待语法稳定下来,尽管正如我之前所说,尽快稳定结构会有所帮助。

@clarcharr我相信我们已经决定稳定该结构以及..=语法,因此我们只需要一些 PR 来实际执行此操作。

编辑:哎呀我错了。 我们正在编译器中实现它,稳定语法需要等待最终评论期结束。 我认为我们应该在这个时候稳定结构,但这也不是我的决定。

我很久以前就停止关注这个主题了,当时在我看来...正在达成共识。 ..=对我来说似乎很尴尬,因为它乍一看就像做作。

但更重要的是,我认为这种自行车棚不足以改变当前的模式语法。

这种语法糟透了!
= 有赋值的意义,即使在 +=, -=, *= 模型中,但 ..= 是关于得到一些东西。 如此混乱和丑陋。
就像数组索引从0开始,'...'很好很漂亮,人们会习惯的。

@曾赛
..=从概念上派生自==<=等运算符,它们已经存在于 Rust 中,表示相等比较,而不是赋值。

(即1..=5是“Range over values 1 <= x <= 5 ”的简写,而不是1..5意思是“Range over values 1 <= x < 5 ”)

编辑:另外,这不是“习惯它”的问题,而是当您疲倦或分心时更难以误读或误打字的问题。 像这样的逐一错误是着名的footgun-y。

当我的意思是..时,我实际上不小心输入了... 。 谢天谢地,我总是以稳定的 Rust 为目标,所以编译器抓住了它。 (但是,假设我想输入伪省略号,我不记得是肌肉痉挛还是肌肉记忆,因为我写了很多非小说类作品。)

@zengsai ...太微妙了,看起来太像..

一种语言有不同数量的点代表不同的东西真的很不正常

取下脚枪比美观更重要。

新人:我做了一个 TL;DR,因为这是一个很长的线程。 你可以在这里阅读: https :

谈到“像这样的一对一错误是着名的footgun-y”,我不得不说:错字问题不应该被用作这一变化的关键原因。

看看这个比较,“..”和“...”与“=”和“==”,这是否意味着我们应该为“==”找到其他语法来避免用户的拼写错误? 如果“=”和“==”很好,为什么“..”和“...”不能?

我已经关注 rust-lang 两年多了。 ant 它被用于我的许多私人项目中。 我喜欢它,但是这种语法确实让我感到不舒服。 不仅美观,还会影响代码的书写和阅读流畅度。

@zengsai我的理解是,这主要不是关于何时_编写_代码,而是关于审查、阅读和理解代码的时间。 如果你不是在寻找它,你可能更容易错过.....作为一个错误的错误,而..=肯定会更突出并获胜没有这个问题。

从美学的角度来看,我不确定我是否喜欢..=语法,但我可以看到每个人都来自.....阅读方式非常相似。

@zengsai因为===的解决方案不适用于.....

当然,您可能会在 C 中混淆=== ......但这是公认的好枪,Python 和 Rust 等更现代的语言解决了这个问题:

  1. 如果你输入if x = y而不是if x == y是一个错误(这是 Rust 和 Python 所做的修复)
  2. 当我不小心输入了x == y;而不是x = y; ,我收到了一个关于无效表达式的警告。

编译器甚至无法识别.....混淆是可疑的,更不用说错误了。

@zengsai .....评估为实现所有相同特征的类型,并且基本上可以互换使用(这是设计使然)。 一个错误的关闭是一个非常现实的问题。

我想明确一点,我也讨厌这种语法,以至于我不同意@aturon的评论,即我们使用..和表达式以及...的当前情况模式是“站不住脚的”; 事实上,我认为断开连接比使用这种语法更可取。

但很明显,我们永远不会就此达成共识,在这个线程上没有新的论点,并且大多数积极投资的用户(以及语言团队的其他成员)都支持这一变化。 所以我站在一边,以便我们可以解决问题。

如果根据我的经验,它有什么安慰的话,绝大多数用例从来不需要真正需要这个功能,所以它不会出现在你的代码中。

实际上,我仍然对在模式中弃用...感到非常不满,我基本上只是要咬紧牙关,以便解决这个问题。 整个 lang 团队都同意,同时拥有.....表达式将是一个可怕的问题,导致一些用户花费数小时来调试一个完全无声的错字问题。

lang 团队的其他成员强烈认为表达式和模式之间存在脱节是不可接受的,虽然我不同意,但我们都提出了自己的论点,我不认为永远处于僵局是健康的。

@ssokolow对不起,我还是不能同意你的看法。 编译器可以警告你这种类型的错字,但是如果你在应该是 "x=6" 的地方输入 "x=5" 怎么办?

编译器不是避免打字错误的完美工具,程序员才是。

如果这个改变没有副作用,我完全同意。 但这让语言失去了审美、写作和阅读的流畅性,这在我个人看来是不值得的。

今天的 rust 已经遇到读写问题了,越是不常见和违反直觉的语法学习曲线就越多,不要让它成为另一个 Perl。

@withoutboats我们与它争论,因为我们喜欢它。 或许这个论点来得太晚了,也改变不了什么,只是……

@曾赛

当然需要权衡取舍,但我的印象是我们永远不会就这些之间的最佳平衡点达成一致。

不管个人品味如何,我认为..=是一个很小的代价,可以避免浪费大量时间来追踪错误。

(我关注的领域是 UI/UX 设计,他们教给你的最大规则之一是,你的目标应该是让犯错的难易程度与它会造成的伤害和/或修复时间成反比。 )

在我看来, 5 vs. 6.. vs ...更明显。

@zengsai我收到太多的电子邮件只是为了这个对话,

@daiheitan 这是正常交流,如果不喜欢,建议你取消定阅该邮件。

当我第一次看到 Rust 时,我真的..语法感到惊讶。 (1..10).sum()是...从 1 到 9 的整数之和? 如果你向一个新手展示这个语法并问他这是什么意思,他很可能会期望它从 1 到 10。他这样做是对的,因为你期望对称语法来表达对称范围。 为什么应该包括 1 而不是 10?

为对称范围添加另一个非对称形式..=使这在视觉上更加不一致。 有人可能会问为什么左边不需要=来包含,所以两边的包含范围都是=..=

类似于Swift 语法..<表示独占, ...表示包含)可以避免这些问题并提高可读性。 即使您完全不熟悉该语言,也可以轻松正确地猜出其含义,因此要记住的事情少了一件。 我原以为会选择这样的东西,特别是考虑到 Rust 对新手友好的推动。

@rkarp在某种程度上,这可能归结于预先存在的偏见。

例如,在 Rust 中有很多 Python 影响并且 Python 使用相同类型的半开范围。 (即,Python 的range(1, 5)myList[1:5]都与 Rust 的1..5具有相同的行为)

在 Python 中这样做的理由是因为只有一种语法,而半开放的语法使得执行诸如head, tail = myList[:pivot], mylist[pivot:]类的事情变得更容易。

也就是说,鉴于 Rust 已经通过了 1.0,对于不破坏现有代码有相当严格的规则。 ..用于排他的外部模式, ...用于排他的内部模式必须保持有效。

..=之所以有效是因为您可以在任何地方接受.. (独占)和..= (包括在内)并将...视为..的弃用同义词在图案中。

只是说,将..=作为令牌在技术上是不兼容的更改,因为它会影响宏中的:tt规则。 可能不会有问题,但您可能需要检查以确保是否有人不这样做,考虑到这也可能是一个安静的变化。 (另一种方法是允许.. /* why not */ = ,我认为这不是一个好主意)

@ssokolow从技术上讲,它是 Rust 中的类型错误,而不是解析错误。 a = 2是一个返回()的表达式,而if期望bool ,因此它们显然不兼容。

规则正在慢慢改变。 从技术上讲, ..=是 3 个令牌,其中前 2 个在它们之后没有空格。

@eddyb :我承认,我并不完全理解。 有没有办法在不影响 :tt 解析它的情况下引入新令牌?

此代码当前报告“规则 2”和“规则 4”。 如果我理解正确,此更改会将其更改为“规则 2”和“规则 5”。

macro_rules! ex {
    ( . . )   => { "Rule 1: . ." };
    ( .. )    => { "Rule 2: .."};
    { . . = } => { "Rule 3: . . = " };
    { .. = }  => { "Rule 4: .. = " };
    { ..= }   => { "Rule 5: ..=" };
}

macro_rules! show {
    ( $($t:tt)* ) => { println!("{}", ex!($($t)*)) };
}

fn main() {
    show!(..);
    show!(..=);
}

不,这是令牌定义方式的变化。 @jseyfried可以更好地解释后果。

从技术上讲,它是 Rust 中的类型错误,而不是解析错误。 a = 2 是一个返回 () 的表达式,而如果期望 bool,那么它们显然是不兼容的。

@xfix谢谢。 上次我打错字时没有引起足够的注意,我仍然不完全习惯于用面向表达式的语言来思考。

我已经调整了我的评论。

我不喜欢..=语法,我反对在模式中弃用... 。 如果我们害怕拼写错误,我们总是可以使用结构RangeInclusive { start, end }而不是.....=作为它的简写。

我刚刚意识到的潜在歧义:

if let 5..=x { ... }

@clarcharr看起来它没有编译。

rustc 1.17.0 (56124baa9 2017-04-24)
error: unexpected token: `=`
 --> <anon>:3:13
  |
3 |     if let 5..=x {
  |             ^^

error: aborting due to previous error

@clarcharr @kennytm
在我们引入..=作为一个操作符后,错误将是:

error: expected one of `::` or `=`, found `{`
 --> <anon>:3:13
  |
3 |     if let 5..=x {
  |                  ^

error: aborting due to previous error

就像现在let x=10; if let 5..x {}

所以这个“歧义”不会编译,因此不会比if let 5..x {}更加歧义。

@Boscop重点是,目前如果我们将5..视为像Some(5)这样的模式,那么if let 5.. = x将类似于let Some(5) = x ,后者编译。 我的评论表明5..不是模式,因此if let引入..=没有兼容性风险。

如果我们确实引入了这个特性并允许..=..在模式中, if let 5..=x应该总是if let 5.. = x并且它应该编译: if let (single expression)没有意义,所以我不相信有任何歧义。

@kennytm所以我们都展示了他们不会编译的 2 种不同的歧义。 (不清楚他指的是哪一个。有点模棱两可,呵呵。)

@daboross就像 kennytm 所说的, 5..不是一种模式,即使现在也无法编译。 如果我们添加..=作为运算符,这不会改变。 没有歧义。 重要的是,现在不能将..=解析为一个运算符,但是一旦我们可以将其解析为一个运算符,就没有歧义了。

5..不是当前有效的模式,我们也没有半闭区间模式。 话虽如此,与范围表达式相比,缺乏半闭区间模式通常被视为不一致的根源,并且最终也可能被实现为模式。 我们还可能希望添加在稍后的模式中省略区间一侧的能力,例如穷举整数匹配。

因此,虽然@clarcharr 的观察不一定指出在考虑当前语法时存在歧义,但在考虑可能与使用..=作为模式的提议相冲突的潜在未来扩展时,这肯定是一种歧义。

考虑到这一点,我建议在这里使用其他一些符号。 ^对我来说似乎还不错,因为它仅用于当前 IIRC 的表达式上下文中。

(这是我认为现在稳定结构和稍后稳定语法是个好主意的另一个原因。)

@nagisa如果在支持 RangeFrom 模式之前添加了令牌..=if let没有冲突。 可以在..=之间添加一个空格来消除歧义,就像x <- y (放置在)与x < -y (小于 + 负数)。

(由于^唯一的-or 运算符,我觉得将..^用于包含范围具有讽刺意味)

在我编写的数千个范围中,其中相当多的范围是完全封闭的,甚至可能有一两个半开放的错误方式,我仍然没有真正看到需要任何额外的语法。 1..(n+1)并不难写。

这不适用于 end = T::max_value()。

2017 年 5 月 29 日 16:33,“Diggory Hardy”通知@ github.com 写道:

在我写的数以千计的范围中,其中相当多的范围完全关闭,
甚至一两个半开的方式都错了,我还是不明白
查看是否需要任何额外的语法。 1..(n+1) 并不难写。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-304662258
或静音线程
https://github.com/notifications/unsubscribe-auth/AApc0ipynL_qrZqUBldOJOX046RNY2H_ks5r-skwgaJpZM4F4LbW
.

我更喜欢半封闭范围的方法而不是 ..= 。

2017年5月29日16:35,“ Simonas Kazlauskas”

这不适用于 end = T::max_value()。

2017 年 5 月 29 日 16:33,“Diggory Hardy”通知@ github.com 写道:

在我写过的数以千计的范围内,其中相当一部分完全
关闭,甚至一两个半开的错误方式,我仍然不
真正看到需要任何额外的语法。 1..(n+1) 并不难
写。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-304662258
或静音线程
https://github.com/notifications/unsubscribe-auth/AApc0ipynL_qrZqUBldOJOX046RNY2H_ks5r-skwgaJpZM4F4LbW
.

我真的希望我们已经用一种构建它们的方法来稳定特征和类型,因为我很确定在这方面没有分歧。 请不要因为语法问题而耽误了核心功能本身的稳定性。

这不适用于 end = T::max_value()。

你真的想迭代 2^64 个值,甚至 2^8 个值吗? 如果您只想迭代例如u32的最后几个值,通常在循环中添加一个更容易。 如果你真的想迭代到2^B-1出于某种晦涩的原因,那么你总是可以将if i == END { break; }放在循环的末尾。

仅仅因为我们的标准无符号整数支持 2^32 或 2^64 值并不意味着可以经常使用最高可表示值。 如果你正在用u8做一些事情,不要忘记 CPU 使用u32作为计数器可能更容易。

但即使我认为不需要封闭范围生成器语法,我也无法反驳团队的 change 论点。 那好吧 :/

这四个如何包含所有包容性选项?

1...10
1>..10
1..<10
1>.<10

我想人们应该能够在没有进一步解释的情况下理解它们的含义,因为不等式运算符从幼儿园开始就已经深入每个人的脑海中......但不知道这些是否会在其他方面造成痛苦。

或者,我们可以转换不等式:

1...10
1<..10
1..>10
1<.>10

......只是为了让最后一个看起来不像一个愤怒的卡特曼。

@vegai那么现有的a..b语法肯定不会被删除呢? 不,我认为建议新的语法选项不会解决任何问题。

嗯,所以提出了两个“潜在的歧义”:

  • if let 5..= x -- 如前所述,现在这不是一个真正的歧义,但它可能有点。 另一方面,这种歧义经常出现,并由分词器解决。 也就是说,如果我们把..=当成我们解析器中的一个token,以后即使添加5..模式也不会产生歧义; 您只需要在..=之间写一个空格(例如, let 5.. = x )。
  • 宏观规则的模糊性。 这确实是一种痛苦和不幸,这也是我们一直在为“宏 2.0”转向不同系统的原因之一,我们避免将“复合令牌”集暴露给最终用户。

    • 最后,如果有必要,我们可以通过一些特殊情况代码处理macro_rules! back-compat; 无论如何,我认为除了使用...之外,无法避免此类问题。

在稳定包含范围之前,问题 #42401 也应该在 imo 中得到修复,因为在稳定之后修复将是一个破坏性的变化。

@est31好点,我将其添加到问题开头的清单中

Checked str 切片本身不稳定,修复该问题根本不会阻止包含范围。

哦, @nagisa是对的,它与范围语法无关。 你能再把它从头上取下来吗? 我的错。 该错误位于get ,因此由str_checked_slicing功能保护:

    impl SliceIndex<str> for ops::RangeToInclusive<usize> {
        type Output = str;
        #[inline]
        fn get(self, slice: &str) -> Option<&Self::Output> {
            if slice.is_char_boundary(self.end + 1) {
                Some(unsafe { self.get_unchecked(slice) })
            } else {
                None
            }
        }
    [...]

移除

Bump:有什么办法可以让结构至少在 1.20 中稳定下来?

我们从 C++ 中借用著名的go-to 运算符用于包含范围语法如何? 😛

@nikomatsakis和 @rust-lang/libs(我不知道如何标记这个),如果我提交了一个 PR,将结构移到不同的跟踪问题,这样我们就可以讨论它们的稳定性,你会有什么感觉那里? 我认为这将是一个很好的方法,可以在我们等待新语法实施/解决期间更快地稳定这些内容。

cc @rust-lang/libs(只有团队中的人可以标记他们或其他团队)

谢谢,@eddyb!

@clarcharr基于https://github.com/rust-lang/rust/pull/42275#discussion_r119211211 ,我怀疑它会受到赞赏。

对于语法建议,我是否为时已晚?
当前看起来就像有人试图将值分配给切片。

for i in a..b {} // [a..b) 
for i in a..+b {} //[a..b] 
for i in a-..b {} //(a..b) 
for i in a-..+b {} // (a..b]

这种语法将使将来无法为范围添加任何Add实现。 我真的不知道这是否是一个问题,因为我不确定Add实现会做什么。

同意尾随加号。 改为前缀。

因为a....b..是 Rust 中的有效构造,这仍然会产生数学运算的歧义:/

a... / a..= / a..+不是有效的吗? 由于包含端点的无限范围实际上没有意义。

我不会太担心Add ,似乎与范围有关的事情并不常见,如果您确实愿意,可以执行(x..+y) + z ?

编辑:没关系,刚刚意识到你的意思。 a..+b是模棱两可的,对吧? 因为现在它意味着a.. + b

@daboross并不是说这是一个好主意或坏主意,但是这个实现(或它的一些变体)可能是我们将来想要的范围:

impl<T> Add<T> for RangeFrom<T> where T: Add<T> {
    type Output = RangeFrom<T>;
    fn add(self, rhs: T) -> RangeFrom<T> {
        (self.start + rhs)..
    }
}

这个特定的 impl 可能是也可能不是一个好主意,但我并没有花太长时间就想出它作为未来可能的用例。 我认为由于现有的语法决定而排除添加此或类似内容的可能性是一个坏主意。

我的另一个担忧是,驳回...的全部意义在于尽量减少难以识别的拼写错误的机会,并允许括号在抽象a..+b两种不同含义之间做出区分。将朝那个方向移动。

此外,我还没有看到a-..ba-..+b的可靠理由,除了“为了完整性,这不是很好吗”,而当前的..和提议的..=都有已知的、有效的理由。

您不能为此使用+ ,因为它会使表达式语法不明确。

编辑:虽然,我想,它会使完全在库中实现包含范围成为可能,因为你最终会实现<Range as Add<{integral}>>::Output = InclusiveRange

我可能会建议..!变体。 它与..押韵富有成效,并特别强调最后一个点,使其更加引人注目。

当然,它会与运算符!发生冲突,但是,老实说,我无法想象需要将!放入绑定子表达式中的情况。

..!在直觉上有问题。 不熟悉语法的新手很容易将..!误解

它还与“范围高达...的按位补码”的语法相冲突(这将使其处于类似于使用+

同意。 但另一方面..=也可能被误解为赋值运算符之一。

如果这是一个赋值运算符,你会赋值给什么?

基于@snuk182的提议:

a...b // [a; b] shorthand for RangeIncusive
a..-b // [a; b) new Range shorthand 
a..b // [a; b) old Range shorthand exists for compatibility

我怀疑我们是否需要其他组合。 无论如何,它可以在以后添加:

a-..b // (a; b]
a-.-b // (a; b)  

虽然最后一个选项看起来有点奇怪。 ^_^

请停止提出任何包含一元运算符的语法,即a..-ba..!ba..*ba..&ba?..b ,这些永远不会公认。

..! 直觉上有问题。 不熟悉语法的新手很容易误解..! 意思是“高达,但不是……”

..=在直觉上也有同样的问题。 任何看到=期待做作或比较。 我承认这个语法完全解决了区分问题,因为每次我看到..= ,我都无法阻止自己想知道这个等号在这里做什么。

唯一既非常直观又与当前语法一致的建议语法是... 。 但船似乎已经航行了。

无论如何,新手都必须经常查看文档。 即使使用...他们也会查看文档。 这是无法避免的。 但是..=有一个很好的助记符( up toequal to ),所以他们不必经常查看这个运算符的文档。

如果...运算符保持原样,而是我们将..运算符更改..⎵ ,即两个点和一个空格(我不得不把那个 '⎵ ' 字符,因为此网页上不会显示常规空格)。 这将是语言中空白很重要的一个地方。 这也将是一个重大变化,因为像a..b这样的所有代码都会抱怨没有像..这样的运算符,并且建议在点之后添加至少一个空格。 我确实认为这个空间使它们在视觉上足够明显:

a.. b
a...b

@tommit 老实说,我认为这不是一个好主意。

运算符目前对空格非常灵活,例如: a..ba .. b是相同的。 这可能是为了使其与其他运算符一致,例如a+ba + b 。 这些当然是一样的,并且允许人们使用不同的语法风格。 如果你问我,那是一件好事!

此外, ..=符号与<=>=符号(也被视为 _inclusive_)一致。

检查还有哪些其他可能性总是好的,但这可能不是正确的解决方案。

同意。 与<=>=..=看起来合理,甚至合乎逻辑。

顺便说一句,如果你是...的粉丝或者只是不喜欢..=外观,那么折衷的解决方案是使用一些带有编程连字的字体,比如FiraCode..=特殊连字... ,甚至是一些奇怪的东西,比如 ⩷、⩦ 或 ≔。

使用范围对所有现有的 Rust 代码进行破坏性更改......到达时死亡,
对不起。 如果有人有一个非常严肃的向后兼容的提议
解决已提出但尚未讨论的问题
已经,让我们听听,但让我们至少将其作为标准,是吗?
这个帖子里到处都是自行车棚,团队已经做出了决定,所以
这是一个需要清除的高标准。

无论如何,似乎仍然有很多关于实际语法的讨论。 我已提交 #43086 以至少稳定结构和特征以及实现,以便可以使用核心功能(似乎有需求,请参阅上面@retep998 的评论)。

房间里的大象是..实际上是这里的真正问题,因为它的外观对称但含义不对称。 “正确的做法”可能需要弃用它,但没有意愿这样做,因为已经有太多代码使用它了。

弃用完全一致的... (对称外观,对称含义)是一种简单的方法,但代价是在..=中添加另一个不一致的运算符。 似乎添加了糟糕的设计来解决以前的糟糕设计。

由于这种双重不一致,因此还有另一个问题:没有添加最后两个包含性变体的好方法(两侧互斥,仅左侧互斥)。 由于....=在左侧已经有一个隐式的= ,我们必须以某种方式否定它,可能使用< 。 所以他们必须看起来像这样:

  • <..=(a; b]
  • <..(a; b)

祝你好运正确猜测这些作为新人的含义。 所以他们可能(理所当然地)永远不会被考虑添加。

如果..没有那么根深蒂固,甚至根本不存在,那么从头开始为所有这些设计一致的设计似乎并不难,例如:

  • .. (或... )为[a; b]
  • ..<[a; b)
  • <..(a; b]
  • <..<(a; b)

我有一种感觉,最后两个变体在某些时候可能会有用,我们真的应该这么快阻止通往它们的道路吗? 在任何情况下,选择..=不是弃用..唯一好理由是破坏的旧代码要少得多,但这充其量只是一种必要的邪恶,没什么值得庆祝的。

_编辑:为了更清晰,添加了一个例子和一些评论。_

我同意@rkarp 的观点,即..是这里的实际问题,而不是.....= 。 考虑到其他(更流行的)语言实际上确实为其分配了对称含义,不对称含义尤其糟糕。 例如,Kotlin、Ruby 和 Haskell 都认为 5 位于 3..5 范围内。 数学论文似乎也赞成这一点。 这里最糟糕的事情是初学者没有机会猜测 3..5 在 Rust 中的行为:你要么决定 4 并且只有 4 是范围 3..5(点上的迭代)的成员,要么两者都3 和 5 也在其中(迭代“我们能看到的一切”和点的外推)。

然而,我不同意改变这一点的难度。 我认为@adelarsq 的建议可以相对

[1..4] // 1, 2, 3, 4
[1..4[ // 1, 2, 3
]1..4] // 2, 3, 4
]1..4[ // 2, 3

任何出现的x..y (不带方括号)都可以转换为[x..y[并发出编译器警告。 在几次发布之后,编译器可以简单地拒绝编译“裸”范围表示法,甚至可能提供自动转换为新表示法的工具。

https://github.com/rust-lang/rust/issues/28237#issuecomment -274216603 这不是一个新想法,由于我们已经提到的原因,我们不能使用它。

我完全同意这样的想法,如果我们从头开始设计语言,事后的好处,我们会想要一起考虑独占和包含范围的语法。 我确实认为..=不是包含范围的理想运算符; 它只是目前桌面上的最佳选择。 但是弃用当前的独占范围运算符会非常痛苦,并且会让现有的 Rust 用户和项目感到反感。

还有许多其他的可以工作的建议。 例如,我还没有看到..@提议,而x..@y似乎确实令人回味。 挑战在于找到比当前提案更引人注目的东西,同时保持没有歧义。

我想强调@ssokolow 2 个月前的评论,作为我最喜欢的对称观点:

  • ..4包含的东西< 4
  • ..=4包含的东西<= 4

我认为我们只需要包含范围,那更简单。
您始终可以添加 + 1 或 -1 来更改范围。
而且 .. 更好,因为 .. 比 ... 更简单!

@AlexanderChen1989正如之前在此线程上的多篇文章中所说,这是不可能的,因为更改..的含义会破坏现有代码。

另外,它实际上并没有那么简单。 最值得注意的是, +1-1会导致整数上溢/下溢。)

这是一个适用于nightly (通过包含范围语法的旧候选)的示例,其中...

  • ...无论您先放置哪个循环,都会在调试版本中出现溢出/下溢时出现恐慌
  • ...它们的行为与发布版本中的预期完全相反(即“0 到 0”将迭代 256 次,而“0 到 255”根本不会迭代)
#![feature(inclusive_range_syntax)]
fn main() {
    let max = 255u8;
    let user_provided = 0u8;

    for x in 0...user_provided-1 {
        println!("(0 to 0, exclusive via 'inclusive - 1'): {}", x);
    }

    for x in 0..max+1 {
        println!("(0 to 255, inclusive via 'exclusive + 1'): {}", x);
    }
}

自从语言团队做出决定以来,已经提出了 8 条到达时死亡的语法建议。 新人请看帖。 我们有很好的理由做出我承诺的决定。

恕我直言,OP 应该更新以指出不应在此线程中进行更多语法讨论,并且任何独占范围语法(即 (a, b) 和 (a, b] 范围) 的建议都应移至另一个线程。

这应该只谈论需要做的事情来稳定当前的计划。

@clarcharr我做出了一个主要是单方面的决定,并将其添加到 OP 中,好主意。 如果噪音继续存在,我会投票支持锁定线程。

你好,我是新手,我想开始研究这个。 我将尝试编写 PR 在模式中添加..=作为...的同义词,在表达式中弃用... ,并显示一个错误,指出语法已更改为..= 。 这听起来正确吗?

@Badel2很酷。 我实际上已经开始了——我很快就会推送我的分支并将它链接到这里。

@durka只是为了澄清-您是否愿意让@Badel2从您的分支机构开始? 作为 impl 时期工作的一部分,你能指导他们吗? 他们在 Gitter 频道中。

我也同意实际问题是.. 。 因此,更有利的解决方案是弃用(不立即替换,因此它会__not__ 破坏现有代码) ..支持诸如..<类的东西( a..<b之间不会混淆(a..)<b ,因为..最终将不复存在)。

@hyst329请阅读已经发表的帖子。

第一个帖子用粗体文字说:“在这个线程中不应该有更多的语法讨论。”

除此之外,没有阅读现有讨论的其他人已经在这里多次提出您所描述的内容,并且给出了多种原因来解释为什么它不是一个可行的选择。

抱歉,这不是很有建设性,但是每次我看到..=并尝试记住它是什么时,它看起来就像一个类似于+=<<=的赋值运算符。 感觉很混乱,它不是。 (尽管不可否认,这已经脱离了上下文,例如“对..=语法的初始支持”https://this-week-in-rust.org/blog/2017/10/03/this-week- in-rust-202/)

@SimonSapin我在上面以更具建设性的方式表达了同样的批评,建议改为..^https :

对我来说, ..=一个重要观点是与 swift 的一致性(它有..<用于独占范围和..用于包含范围)。 这让我可以接受..=

@SimonSapin我认为没有人对此完全满意。 问题是,数百条评论不幸地证实了没有更好的选择。

这个补丁让我相信比什么都不做要好,只是为了覆盖边缘情况而弄乱当前的模式语法。

..在模式中的用例很少,没有它你总是可以处理的。

在真正需要它们的表达式中, ...可以替换为RangeInclusive(Bound<T>, Bound<T>) 。 它更冗长但易于理解。

@UtherII

...并且我确信...是站不住脚的,因为编译器的“您不能在稳定版上使用包含范围语法”消息使我摆脱了一个微妙的错误。

当您快速连续按下多次时,很容易意外地多次按下. (或者,考虑到所涉及的机制,一次太少)。

我已经勾选了“在模式中接受..=作为...同义词,并在表达式中接受..= ”,因为在 #44709 之后已经是这种情况了dotdoteq_in_patternsinclusive_range_syntax分别具有特征。 剩下的只是文档和稳定性。

要求稳定

我想将包含范围稳定在1.26 (3 月 30 日测试版,5 月 11 日稳定)或更早。 稳定 PR 已作为 #47813 提交。

概括

将稳定以下 3 个功能:

  • inclusive_range_syntax — 表达式中的a..=b..=b语法:

    for i in 1..=10 {
        println!("{:?}", &a[..=i]);
    }
    
  • dotdoteq_in_patterns — 模式中的a..=b语法:

    match c {
        b'0'..=b'9' => c - b'0',
        b'a'..=b'z' => c - b'a' + 10,
        b'A'..=b'Z' => c - b'A' + 10,
        _ => unreachable!(),
    }
    

    (注意: a...b语法仍然被接受,没有警告)

  • inclusive_rangestd::ops::{RangeInclusive, RangeInclusiveTo}类型及其字段:

    let r = 1..=10;
    assert_eq!(r.start, 1);
    assert_eq!(r.end, 10);
    

文档

@alercah提交了几个文档 PR,谢谢!

测试

您可以在以下位置找到测试用例:

未解决的问题

  • 在 for 循环中使用a..=b性能比a..(b+1)低得多,因为它的next()更复杂且对优化器不友好。 目前正在#45222 中跟踪此问题。 当使用迭代器方法而不是 for 循环时,#48012 目前可以缓解这种情况。

    如果我们还不想提交 rust-lang/rfcs#1980 中的设计,我们可能需要保持RangeInclusive的字段不稳定。

如果我们还不想提交 rust-lang/rfcs#1980 中的设计,我们可能需要保持 RangeInclusive 的字段不稳定。

+1
是否需要直接公开范围字段,而不是通过一些基于方法的接口?

@rfcbot fcp 合并

根据@kennytm的总结,我建议我们稳定包含范围语法( ..= )。

(不过,我的确发现的较低性能的..=温和有关,我不知道它是否有意义,使..=不能直接实现Iterator暂时在以减轻这种情况。)

团队成员@nikomatsakis已提议将其合并。 下一步是由其他标记团队进行审查:

  • [x] @BurntSushi
  • [x] @Kimundi
  • [ ] @KodrAus
  • [x] @alexcrichton
  • [x] @aturon
  • [x] @cramertj
  • [x] @dtolnay
  • [x] @eddyb
  • [x] @nikomatsakis
  • [x] @nrc
  • [x] @pnkfelix
  • [x] @sfackler
  • [ ] @withoutboats

当前未列出任何问题。

一旦大多数审稿人批准(并且没有人反对),这将进入其最终评论期。 如果您发现在此过程中任何时候都没有提出的重大问题,请说出来!

有关标记的团队成员可以给我的命令的信息,请参阅此文档

我想知道让 ..= 暂时不直接实现 Iterator 是否有意义,以减轻这种情况。

这些稳定的特征在当前 Nightly 中至少T的一些RangeInclusive<T>实现: IteratorFusedIteratorExactSizeIteratorDebugCloneEqPartialEqHashTrustedLen

@SimonSapin我忘了,我们已经稳定了结构吗? (换句话说,这是可观察到的吗?)我假设它不是。

也就是说,我也真的,真的认为1..21..=2应该在所有相同的地方都可以使用,这反对在这里进行任何更改,而是建议我们应该只寻求缓解措施和改进优化。

为什么不在end == MAX特殊情况范围内? 这可能导致大多数包含范围与独占范围具有相同的代码,但直接进入边界的范围具有更多代码。 因为end != Max分支永远不会修改end ,所以它很容易被优化器内联。

@nikomatsakis不,目前结构不稳定。 但是@kennytm 的提议包括稳定它们。

@西蒙萨平

不,结构目前不稳定。 但是@kennytm 的提议包括稳定它们。

我明白; 事实上,这就是为什么我提到我们现在或永远都必须删除Iterator impl。 =)

@SimonSapin我不认为我们可以在不稳定结构的情况下稳定a..=b表达式语法。 然而,如果我们确实认为我们可以改变它,我们可以让这些领域不稳定。

是的,我并不是说在稳定用于构造这些类型的值的语法时我们不应该稳定这些类型。

Huzzah 用于逃避范围语法自行车棚和稳定! :tada:

给定一台时间机器,我认为 Range 类型中没有一个是:Iterator ,而它们只是:IntoIterator 。 但就像现在一样,我认为与 Range 保持一致是最好的选择。 我们可以将这种情况与Chain放在“好吧,结果内部迭代有时

另一件事未解决,也与迭代有关:一旦完成迭代,我们是否要承诺 RangeInclusive 的任何特定表示? 现在它以1..=0 ,但讨论了其他选项。 我不知道文档是否足以阻止人们依赖它,尽管当前的文档确实使迭代后范围变得毫无用处,这至少不鼓励它。

我们可以将 Chain 的这种情况放在“好吧,结果内部迭代有时更快”的桶中。

我认为我们确实需要修复它以使其性能不低于独家范围; 没有根本的原因。

没有_根本_原因。

这取决于我们可以强制执行哪些不变量。 在前两个带有额外状态位的公式中,当我们完成迭代时,没有强制执行该位实际上已设置(实际上它 _wasn't_ 设置在诸如100..=0类的文字上),因此循环退出条件需要复合,这意味着 LLVM 不再愿意为我们展开它,因此我们的性能变得更糟。 完全修复这似乎意味着要么使结构更大并且没有 pub 字段,要么使RangeInclusive: !Iterator ,或者使 LLVM 更好地优化这些类型的循环。

也就是说,我尝试了一些不同的编写RangeInclusive::next ,看起来我过去自己选择匹配Option<Ordering>使 LLVM 非常难过——只是将比较运算符放在那里而不是给出更好的组装。 编辑PR: https :

给定一台时间机器,我认为 Range 类型中没有一个是 :Iterator,而它们只是 :IntoIterator。 但就像现在一样,我认为与 Range 保持一致是最好的选择。 我们可以将 Chain 的这种情况放在“好吧,结果内部迭代有时更快”的桶中。

我基本上同意这一点。

:bell: 根据上面的评论

:bell: 根据上面的评论

@rfcbot fcp 取消

@withoutboats@KodrAus没有检查他们的箱子。

@cramertj提议被取消。

团队成员@cramertj已提议将其合并。 下一步是由其他标记团队进行审查:

  • [x] @alexcrichton
  • [x] @aturon
  • [x] @cramertj
  • [x] @dtolnay
  • [x] @eddyb
  • [x] @nikomatsakis
  • [x] @nrc
  • [x] @pnkfelix
  • [x] @sfackler
  • [ ] @withoutboats

当前未列出任何问题。

一旦大多数审稿人批准(并且没有人反对),这将进入其最终评论期。 如果您发现在此过程中任何时候都没有提出的重大问题,请说出来!

有关标记的团队成员可以给我的命令的信息,请参阅此文档

:bell: 根据上面的评论

@rfcbot fcp 关注范围模式有一个操作员优先级问题 - https://github.com/rust-lang/rust/issues/48501。

@petrochenkov语法是<strong i="6">@rfcbot</strong> concern KEYWORD ,没有fcp 。但是我认为只有标记的团队成员可以注册一个问题。)

最后的评论期现已完成。

如果#48501 足以阻止稳定,我想我们必须推迟等待#48500 合并(并稳定)? 呃,希望我们能找到一条更快的路。 此功能已经出现了很长时间,现在处于不稳定的状态,错误消息将人们指向不稳定的语法。

@杜尔卡
我认为这种稳定不需要等待稳定https://github.com/rust-lang/rust/pull/48500。
...仍然存在并且它仍然具有旧的优先级,所以如果你在模式中有&BEGIN ... END (我怀疑这应该很少见),总是有一个选项不将其更改为..=一段时间。

我认为我们可以很快稳定#48500

就我个人而言,我可以将它“稳定”登陆

inclusive range已经稳定,因为#47813 拉取请求已经合并,但它不在 1.25 版本中,为什么? 虽然拉取请求是在3 月 16 日合并的

@mominul功能只有在合并到 master 分支后才可用,因此..=从 1.26 开始可用,而不是 1.25。

这样你就可以在它们被推到稳定之前在测试版和每晚测试它们。

感谢@kennytm@clarcharr的输入! Rust 1.26 版本至少对我来说绝对不无聊! :微笑:

我知道现在参与这个讨论为时已晚,但为什么不完全省略..语法而使用单词呢?

在 Scala 中,您有1 to 4生成[1, 2, 3, 4]1 until 4生成[1, 2, 3] ,以及后面的可选的by关键字,表示步长: 1 to 10 by 2 = [1, 3, 5, 7, 9]

这既使意图更加明确,又避免了每个人似乎都很关心的“一对一”错误。

当然,如果不支持原始语法,这确实会破坏所有现有代码。

rust范围内的tountil作为关键字来支持这一点,这将是一个更大的突破性变化。

它在 Scala 中运行良好,但 Rust 的设计选择差异很大。

@ElectricCoffee虽然我喜欢那种感觉,但我认为不需要为它添加额外的关键字。

我认为应该将内置语言关键字保持在最低限度,因为它们可能会与函数或变量名称发生冲突。

尽管tountil不是std (据我所知),但我确定它们是其他 crate 中使用的常用词,并且项目。

@daboross这实际上是一个我没有考虑的公平点,尽管如此说, a .. b在某种意义上确实意味着a to b ,无论ab实际上是。

是的, @timvisee他们可能是。

@ElectricCoffee但是如果to意思是..=until意思是..你就必须写a until b ,而不是a to b而不是a .. b 。 正如你所看到的,这不是“更加”直观地用这句话不是运营商。但它会更详细写until到处是..使用,因为它比更常见..= (所以如果使用单词, ..应该被指定为较短的单词)。

你对@Boscop说得完全正确,但这只是一个如何完成文字的例子。

我相信在某些语言中,我已经看到to表示独占和upto表示包含。
这一切都只是一个想法。

在 Scala 中,包含范围比排除范围更常用,因此给出较短的词。

@timvisee可以简单地使用a.to(b)a.until(b) ,不需要额外的关键字(并且它不会使语法变得更加笨拙)。

@hyst329我什至没有想过。 我必须说,我真的很喜欢这个主意! 你确实是对的。

我不相信这将是当前 (/new) 语法的正确完全替代。 但这将是一个很好的补充。

我不得不同意 Boscop 关于直觉的评论。 除了像“包括”和“除外”这样的词外,日常英语并没有真正区分包含和排除范围,足以有一个现成的捷径。

除非它用于还使用“A 到 B”的上下文中,否则在加拿大安大略省南部的日常讲话中,“A 到 B”是指包含还是排除范围是不明确的,并且“直到”是相关联的随着时间的推移,当在这种更宽松的意义上使用时,不清楚“直到”所关联的“事件”是“直到我们看到X”还是“直到我们处理了X”。

@hyst329但是,将它们作为方法会将范围限制为数字类型。 我真的宁愿没有一种用于数字范围的语法和另一种用于其他事物范围的语法。

我想我们可以在创建范围的前奏中添加一个新的包罗万象的特征,但是对于具有实际tountil方法的事物来说,这仍然是一个突破性的变化。

我承认,我认为关键字的建议是愚人节玩笑。
..= 语法已经稳定。

2018 年 4 月 5 日星期四下午 1:53,David Ross [email protected]写道:

@hyst329 https://github.com/hyst329将它们作为方法会限制
不过,范围为数字类型。 我真的宁愿没有一种语法
数字范围和其他范围。

我想我们可以在创建的前奏中添加一个新的包罗万象的特性
范围,但对于具有
实际到和直到方法。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/rust-lang/rust/issues/28237#issuecomment-379021814
或静音线程
https://github.com/notifications/unsubscribe-auth/AAC3nwBj-b985q1Ez0OHDEHkG6DWV_5nks5tlloZgaJpZM4F4LbW
.

是的,我们在这个问题上有 300 多条评论,第一条评论说:

在这个线程中不应该有更多的语法讨论。 在您阅读了此处的所有现有评论及其基本原理后,应在用户论坛或内部论坛上提出任何不同的独占范围语法建议。 值得注意的是,打破向后兼容性是不可能的。

我现在要锁定这个问题,对不起,如果我踩到任何脚趾!

我相信这个问题所涵盖的一切都已经完成。 如果还有其他问题,请重新打开并更新问题原始消息中的清单。

此页面是否有帮助?
0 / 5 - 0 等级