Rust: 默认参数和关键字参数

创建于 2013-06-06  ·  70评论  ·  资料来源: rust-lang/rust

我没有看到关键字参数有任何问题,未来有什么计划吗?


注意:错误跟踪器不是进行设计讨论的地方。 请将所有设计讨论定向到 etherpad ( https://pad.riseup.net/p/hvbg6dQQnEe7 ) 或在 wiki 上创建一个自行车棚页面。

以太垫:

最有用的评论

Triage 2013-08-05:没有进展(我知道),虽然它仍然很整洁; 也许声明语法看起来像

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

其中 RHS 是任何常量 expr(即在static声明中有效的东西)。

所有70条评论

没有任何计划,尽管还没有人表示任何反对。 这个问题我考虑了很久,基本上归结为对默认参数的请求。 我想它看起来像:

fn foo(bar: int, qux=2: int, ham=0: uint) { ... }

然后可以将其称为foo(1)foo(1, 3)foo(1, ham=4)foo(6, 7, 8)等。

编辑:请参阅下面 huonw 建议的语法,它与当前的声明语法看起来更好,更统一。

Triage 2013-08-05:没有进展(我知道),虽然它仍然很整洁; 也许声明语法看起来像

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

其中 RHS 是任何常量 expr(即在static声明中有效的东西)。

IMO 这些真的很有用,即使是 _default arguments_ 的 C++ 系统,在这种系统中,您只能回退到未指定参数的默认值,这会很棒……减少备用命名函数变体的数量,同时又不像重载那样复杂。能够在结构和枚举变体中声明那些会很棒。
也许在就如何/是否调用命名关键字参数达成共识之前,可以实现所需行为的这个更简单的子集......它会让内部准备好?

根据早期指定的参数和泛型类型参数(例如……查找零的能力:, 或者像这样写 slice(&self, start:uint , end:uint=self.len ()) /* "foobarbaz".slice(6) == "baz" .. 或者 create_window(parent,x,y, width :uint=parent.width ()/4, height:uint= (width_161)/100) /_ 默认是黄金比例形状的窗口,如果你根本没有指定大小,则为 1/4 屏幕宽度.. */ .. .. 或者这听起来像是代码膨胀的秘诀..

c++ 样式默认值会排除类似 haskell 的部分 functoin-application,但我听说不太可能进入?

这是默认参数的另一个想法。 我们允许使用_调用存在默认值的参数,而不是完全省略参数。

所以给出@huonw的可爱例子:

fn foo(bar: int, qux: int = 4, ham: Option<int> = None) { ... }

...我们可以调用它作为foo(1, 2, None)foo(1, _, Some(1))foo(1, _, _)等。

然而,考虑到它仍然严格定位,这个想法不会真正为采用关键字参数带来任何好处。

将标题更改为“默认参数和关键字参数”。

未实现,但我尝试添加到 ast & 解析器; https://github.com/dobkeratops/rust/compare/default_args ,这是正确的方法吗? (选项@expr .. 它需要限制 expr 可以是什么?)
将脚趾浸入水中以试验此功能。
我很想增加可以翻译的 C++ api 的子集,它们绝对是我在 C++ 中遗漏的东西,并且命名关键字功能将比 C++ 更棒。
使用第二个建议的声明语法似乎简单而合乎逻辑

@dobkeratops看起来不错(尽管type Default = Option<@expr>可能是不必要的)。

expr的约束在rustc::middle::check_const ; 你必须添加一个像check_fn这样的函数来检查每个参数。 (另外,大概应该有一个检查,默认参数只出现在最后;我想在类型检查器rustc::middle::typecktrans也需要有一些东西。 )

好的,该字段已命名,因此这就是 un-necasery 注释。
感谢您提供有关在哪里查看的指示,我正在查看 rustc::middle::typeck::.. mod.rs (check_fn something )。

以“持续集成”的名义,我是否值得将琐碎的基础工作作为 pr 提交,如果我失败了,也许更了解代码库的人下次可以更快地完成其他部分。
我总是对不同的变化感到偏执

如果你确实决定_反对_他们,它唯一的破坏性是什么?

有人建议这种事情可以用 -Z 选项(..Session::debug_opts...但我没有发现这些东西目前到处传播(例如在解析器中)。

我可以看到您可能会反对编译器解析它尚未使用的内容,我可以将其从警告更改为错误,也许...

@dobkeratops请注意,目前还没有官方开发人员对此发表评论,因此不太可能接受任何 PR。 这里有很多关于 1) 是否需要默认参数的讨论,2) 如果需要,语法应该是什么,以及 3) 我们是否需要关键字参数(因为我们为默认参数选择的语义可能会排除这种情况)。

好吧,我猜他们在很长一段时间内的优先级都非常低,因为他们不会阻止任何事情(他们当然不是我自己的愿望清单的首位)。
只是认为它可能是悬而未决的成果,以及 C++ 人的另一种熟悉感..
我想宏有时可以做类似的工作(甚至更多)。我可以为常见/不常见的变化养成更好的命名习惯

我可以看到命名参数并不重要,但 IMO 可选参数有点重要。 因为在某些地方,我想我看到了一些具有相似签名和相似名称的方法,只是为了在不需要给定 arg 时提供更简单的接口。 如果我们最终因为缺少某个功能而使用这样的遗留功能,那就太糟糕了。

这里有很多微妙的部分。 任何默认参数都是重载的隐式形式,因此(我猜)可能会与特征解析算法和/或类型推断集成。 这可能不是特别困难,但值得仔细设计,此时我不确定我们是否有时间预算。 作为 _language_ 功能,我想它是向后兼容的; 作为 api 功能,它可能会通知 api 设计一些,因此代表 bc 风险。

@Seldaek我同意,如果我们想要默认参数,那么在我们承诺 stdlib 向后兼容性之前实现它们很重要。 但是,我知道至少有一种语言 (Go) 在哲学上拒绝默认参数,而支持具有稍微不同的名称和签名的函数方法。

然而,与 Rust 不同的是,Go 有一些特性可以减少默认参数的缺失。 一方面,它们具有可变参数功能。 [1] 其次,您可以在创建结构时省略字段,这意味着很容易将配置结构传递给函数(省略的字段似乎设置为编译器指定的(?)默认值,而不是用户可以自定义))[2]

对于前者,我们或许可以通过宏黑客来实现相同的结果(尽管付出了艰巨的实施成本)。 事实上,即将到来的fmt!()替代品就是这样做的:

ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3)

这是今天有效的代码。

至于后者,我们所拥有的最佳模拟是使用功能结构更新,如下所示:

struct Foo { x: int, y: int, z: int }

impl Foo {
    fn default() -> Foo {
        Foo{x: 0, y: 0, z: 0}
    }
}

fn bar(f: Foo) {
    printf!(f);
}

fn main() {
    bar(Foo{y: 5, ..Foo::default()});
}

我已经看到这种方法在过去被随意建议作为缺乏默认参数的一种解决方法,但它在实践中非常笨拙(将bar(Foo{y: 5, ..Foo::default()})bar(y=5) ,或者我更保守的bar(_, 5, _) ),当然它会强制所有调用者创建一个结构,即使他们_do_想要传递所有参数。

重申一下,作为来自 Python 和 Javascript 的人,我显然欢迎默认参数。 但是,我对 Go 使 API 显式化的哲学有些同情(以换取(可能极大地)夸大 API 本身中的函数数量)。

[1] https://groups.google.com/d/msg/golang-nuts/NWMReL1HueQ/X9mdYduCOB8J

[2] http://stackoverflow.com/questions/2032149/optional-parameters

我还应该指出,它与闭包交互并采用对函数的一流引用。

@bstrie感谢您对 Go 的概述。 我同意重载可能是一个坏主意,因为它会创建令人困惑的 API。 同样,jQuery 的“重载”方法几乎可以在您想要的任何参数中进行回调,这非常奇怪并且难以实现。

我有点同意填充默认参数的包装函数在某些情况下并没有那么糟糕。 但问题是,虽然它使您免于一些令人困惑的情况,但它确实在其他情况下引入了很多样板。 一个例子是*::to_str_radix(num, radix) 。 如果我们有可选的 args,这很可能被折叠在*::to_str(num, radix = 10) 。 我觉得在某些情况下,函数变体的爆炸式增长确实让事情变得不那么直观和难以记住。 显然只是我的两美分。

我可以看到推迟它们是一个很好的时间权衡;
但是确实_真的_在哲学上省略了默认值,还是只是它们证明了他们所做的实施时间预算权衡的合理性? 如果有人认为深入研究 long_function_names_with_lots_of_trailing_qualifiers 是向前迈出的一步,我会感到惊讶 :) 但如果他们说“它让我们利用简单的工具,我们还没有开发出强大的 IDE ......”那是另一回事。

我绝对想念 C++ 的重载和默认值......但我很高兴用它们换取 Rusts 的其他便利和 C++ 替代方案的承诺(在被一种主要语言困住了这么久之后......)

对于一个实验,我想尝试将它们作为“解析器黑客”......在宏级别工作? 在缺少参数的调用站点上内联默认表达式?
我意识到这不太可能是一个可以接受的设计 - 但它让我相信它不是_不可能_拥有与 rust 功能一起使用的默认参数。

我仍然真正习惯的一件事是,理论上方法在 Rust 中更有用。
回到 C++ 我害怕它们,因为头文件/依赖问题,(这是我在这里的主要原因),所以我经常本能地首先去寻找函数。
也许当我更好地使用 Rust 时,我会更少地错过默认值..

只是为了这个想法不会消失: bar(Foo{y: 5, ..Foo::default()})的健谈方面在我看来是..Foo::default()部分。

如果我们在结构体构造中更容易地省略字段,让它们成为默认值,那么这种方法可能会更可口。

例如,一个新的形式,可能只为实现一些适当特征( ZeroDefault或其他)的结构定义,看起来像这样:

Foo{y: 5, *)其中*代替了之前的..Foo::default()

那么这个例子是“只是” bar(Foo{y: 5, *}) 。 也许其他人更喜欢Foo也不在那里,但这对我来说似乎很干净。

我想枚举还为您提供了一些其他方法,可以方便地传递可选参数组,这与 C++ 程序员习惯的不同……以及一种通过调用散布注释和值的方法。
这似乎很适合创建具有大量设置参数的东西的情况

@pnkfelix请记住,该Foo结构可能具有更具自我描述性的名称,即使使用您提议的糖,在实践中也会看起来像这样:

html::start_server(html::ServerOpts{port: 10088, *});

它确实看起来更好一些。 仍然不确定它是否足以保证新语法,或者它是否足以满足默认参数的所有用例。

事实上,以我自己的例子为例,当初始化一些有很多选项的东西时,比如 HTML 服务器,我可能会很高兴事先设置一个server_opts结构,然后只调用start_server(server_opts) . 如果我的结构初始化已经跨越多行,我真的不介意用..html::ServerOpts::default添加一行。

我想也许我们需要重新考虑默认参数在哪些方面最有用。 对我来说,这不是有很多潜在争论的地方; 这些应该很少见,几行来初始化配置结构就可以了。 相反,当 1) 操作相当常见,并且 2) 操作最多有一个或两个几乎总是多余但为了完整性所必需的参数时,我最会错过默认参数。 例如:

let foo = Some('a');
foo.unwrap();  // same as today
foo.unwrap('z');  // imagine that this replaced unwrap_or_default

int::from_str("4");  // same as today
int::from_str("4", 16);  // imagine that this replaced from_str_radix

然而,既然我已经输入了这些,我实际上更喜欢单独方法的明确性。 :) 也许我真的不知道我到底想要什么!

@dobkeratops ,根据您使用 C++ 的经验,您能给我们一些默认参数启用的漂亮 C++ API 示例吗?

https://github.com/mozilla/rust/wiki/Meeting-weekly-2013-08-13 中的评论似乎表明开发人员认为这是一个遥远的未来功能。 提名。

我相信 OCaml 在没有重载的情况下执行可选/默认参数。 没有默认值的 T 类型的可选参数被隐式转换为 T 选项,函数必须检查是否提供了值。 对可选参数的声明和使用也有限制,以使编译器知道何时省略了参数。 所有可选参数都必须有标签(它们必须是关键字参数才能成为可选参数)。 这使 OCaml 的类型系统复杂化(标签成为函数类型的一部分),但我认为这是必须与 Hindley-Milner 类型系统的其余部分进行互操作的人工制品。

来自 C++,我真的会想念默认参数值。 我经常使用带有大量参数的函数,其中大多数几乎总是有默认值,除了一些罕见的使用或测试用例。 添加纯粹的组合函数名称导数代替默认值,会造成一大堆非常长的名称。

我同意默认参数和/或关键字参数将非常有用。 我认为我们应该朝着 1.0 之前的提案努力,该提案概述了在重载方面需要做的事情,并且可能对语法进行讨论。

很高兴看到更多人评论赞成 :) 我想要它的另一个原因是增加可以无缝翻译的 C++ API 的数量。 使用 C++ 库是我们坚持使用 C++ 的一大原因。

我怀疑如果社区可以_实现它_而不会给核心开发人员带来任何成本,我们就会得到它。
我同意他们有更重要的事情要做,并且枚举可以恢复丢失的多态性,而这些可能性对于 C++ 条件反射的大脑来说并不明显。

这就是为什么我想提交将其解析为 AST 数据结构的基础工作。 它可以让其他人拿起它并尝试找到解决方案。 最初的反馈让我不敢做 PR。

从 C++ 我羡慕地看着 Scala 和 python 对此有什么看法。 具有这种优雅的本机非 GC 语言会很棒。
..它在一个地方有更多的功能,更少的导航来弄清楚发生了什么,更少的嵌套深度,更少的源代码中的噪音。 不仅仅是简单地减少打字。
也许您甚至可以声称它具有更多的自我记录功能,函数签名会告诉您更多有关其使用方式的信息。

它认为,困难的一点是类型检查器,如果它只是作为解析器黑客完成,则可以防止细微的错误可能性和令人困惑的错误。

想象一下,如果你能写出这样的东西..

fn substr(a:&str, start:int, end:int=a.len())->~str

只需在没有错误检查的情况下将这类东西 hack 到 AST 中,我相信很多都会出错..但是想象一下我们是否可以修复它以实现预期的效果:)

只是一个错误。 我们可以辩论优点,但不会阻止发布。

我喜欢@tautologico在他的评论中描述的行为。

应用于 Rust,我相信这将转化为以下内容:

fn ga(bu: int, zo: Option<int>, meu: Option<int>) {
  let zo = zo.get_or_default(42);
  let meu = meu.get_or_default(99);
  ...
}

这些都是有效的调用:

ga(10, 20, 30); // 20 and 30 are automagically
                // converted to Some(20) and Some(30)
ga(10, 20);         // ga(10, 20, 99) 
ga(10);             // ga(10, 42, 99)
ga(10, None, None); // ga(10, 42, 99)
ga(10, 20, None);   // ga(10, 20, 99)
ga(10, None, 30);   // ga(10, 42, 30)

规则是可以省略尾随的Option<T>参数。 这里重用了Option类型,但如果这会导致一些问题,则可以创建另一个更具体的OptParam类型。

这个提议允许调用者精确地选择他想要提供的参数和他想要保持默认的参数,而与其位置无关。 另外,我认为默认值没有出现在参数列表中是一件好事。 这样,默认值不限于常量表达式,它可以取决于对象的状态,也可以取决于其他参数。

显示 GUI 对话框的函数的真实示例:

fn showDialog(message: ~str,
              parent: Option<Widget>,
              title: Option<~str>,
              type: Option<DialogType>,
              icon: Option<Icon>) { ... }

// Display an info box in the middle of the screen.
// Set the title to "information", translated in the current locale
// Set the icon to an "info" icon
showDialog(~"hello, world!");

// Display a warning box in the middle of the screen.
// Set the title to "warning", translated in the current locale
// Set the icon to a "warning" icon
showDialog(~"sick, sad world!", None, None, WarningDialog);

// Display a warning box in the middle of the screen.
// Set the title to "warning", translated in the current locale
// Set the icon to a custom icon
showDialog(~"sick, sad world!", None, None, WarningDialog, bugIcon);

在这个例子中:

  • parent的默认值为None (无父级)
  • type的默认值为InfoDialog
  • icon的默认值取决于type
  • title的默认值取决于type和当前语言环境

您现在还提议添加Option作为新的原始类型。 它现在完全是一个库功能,因为它是一个普通的旧enum

我想补充一点,使用关键字 args 时,IMO 默认参数要好 10 亿倍。 我不喜欢默认参数但没有关键字参数的想法。

一个是另一个的垫脚石,默认值本身仍然有用,你有一些额外的标志..如果你只想要默认值,可以不使用它们..
同意,如果你两者兼而有之,它们就会结合得很好。
关键点实际上是实施它们:)
如何将其改装到类型检查器/类型推断器中……或者如何将其插入。

位置参数的默认值会产生神秘的代码。 为什么不仅有关键字参数的默认值? (如果这些被实施)。

IMO ......它不是“非此即彼”。
他们两个都很有用。 一种更易于实现,在语法上的选择较少;
所以对于我们来说,作为垫脚石,或者首先尝试实施它是有道理的......

与普通函数调用相比,省略默认值如何更神秘? C++ 程序员已经习惯于对 thsi 的参数进行排序。 通常某种控制标志字在末尾带有合理的默认值.. 只需省略该值而不是写入 (..,BLAH_DEFAULT) 任何内容.. 通过仅列出重要信息来澄清。 需要 Rust 的人可能已经接触过 C++,因此已经习惯了。

我今天早些时候意识到我上面的提议(它试图利用现有的结构扩展语法来提供接近默认参数的东西,因为我认为结构已经提供了关键字参数的成分),忽略了一个重要的问题:我提议的语法假设可以为 _every_ 参数提供默认值(然后它们都将被提升到单个结构参数中)。

这在一般情况下当然不是真的:一个人经常有一些参数是必需的,而另一些是可选的。

我仍然想找出一些方法来利用我们已经拥有的特性,而不是进一步使用函数声明语法,主要是因为函数声明_已经是毛茸茸的_多亏了人们可以写下函数/闭包/方法的各种方式。


我目前的头脑风暴集中在我们是否可以利用现有的结构体语法,也许通过在结构体项的定义中为字段添加默认表达式。 这将允许一个人拥有一些可以删除的字段和其他需要的字段。 就像是:

struct Foo { x: int = 0, y:int = 0, z:int = 0 }

fn bar(f: Foo) {
    printf!(f);
}

struct Baz { x: int, y: int, z:int = 0 }

fn quux(g: Baz} {
    printf!(g);
}

fn main() {
    bar(Foo{y: 5});
    quux(Baz{y: 5}); // ~ERROR: required field, `x`
}

@pnkfelix我喜欢这个建议,也许利用相同的内部结构但生成匿名结构并不会太难。 因此,以您的示例为例,这实际上是相同的代码,带有一点编译器魔法来推断结构:

fn bar({ x: int = 0, y:int = 0, z:int = 0 }) {
    printf!(f);
}

fn quux({ x: int, y: int, z:int = 0 }) {
    printf!(g);
}

fn main() {
    bar({ y: 5 });
    quux({ y: 5 }); // ~ERROR: required field, `x`
}

@visionmedia @bstrie我们真的需要担心摆脱结构名称吗? 重新绑定使用声明是否解决了长名称的问题,通过将调用站点的最小附加字符数降低到 3(对于名称 + 左右括号)?

即,使用 bstrie 向我提出的 ServerOpts 示例:

fn main() {
  use O = html::StartServerOptions;
  ...
  html::start_server(O{port: 10088});
}

@pnkfelix我喜欢

struct Foo {
   x: int = 10,
   y: float = 1.0
}

语法,但我认为我们不需要它来获得合理的强制参数(不幸的是没有命名),只需单独传递强制参数:

struct FooOptions { ... }
static default: FooOptions = FooOptions { ... };
fn foo(compulsory: int, required: uint, necessary: float, optionals: FooOptions) { ... }

FWIW,我也喜欢具有默认值想法的结构。 我想这将是一个捷径:

struct Test {
    m: int,
    y: int
}

static DEFAULT: Test = Test{m: 10, y: 15};

Test{y: 5, ..DEFAULT}

我也喜欢定义中的结构默认值

我也用这种语法进行了解析,但没有实际使用过..我仍然不知道我在类型检查器源等方面的方法......

也许已经有一个默认机制的事实可能使它更容易实现。

回覆。 匿名结构我认为他们最初有那些但不得不删除它们“因为奇怪的交互”?
我希望这两种机制都可用。 也许参数结构会减少对 _keyword_ 参数的需求,但是像 c++ 中的尾随默认值仍然很方便

以供参考 -
http://www.parashift.com/c++-faq-lite/named-parameter-idiom.html
大声笑 - 有趣但真实的关键字参数将避免需要像这样的样板重击

回覆。 匿名结构我认为他们最初有那些但不得不删除它们“因为奇怪的交互”?

最初所有的结构类型都是结构性的。 我相信,由于与特征的尴尬交互,它们被删除(替换为名义结构类型)。

我喜欢结构定义想法中的默认值。 这似乎很容易理解,并且至少避免了在构造结构时必须枚举每个字段 - 这是“选项”类型结构的问题,因为这意味着当添加新的“可选”字段时,必须将每个调用站点修改为将其初始化为 0/None/等。

来自 Perl(其中默认值是临时模式)、Python 2(您可以获得foo() takes at least 2 arguments (2 given) )和 Python 3(您可以拥有仅命名参数 _without_ 默认值),我谦虚地建议:添加一个 _teeny_ 糖,允许将结构声明为函数的最终参数,但让调用者 _inline_ 结构字段。

例如

impl int {
    struct FromStrOptions {
        radix: uint = 10
    }
    fn from_str(s: str, opts: FromStrOptions) -> int {
        // ...
    }
}

int::from_str("4", radix: 10);

好处:

  • 函数定义没有新的语法,实际上根本不需要关心调用者如何调用它。 这类似于使用do传递块的工作原理:这纯粹是调用者所关心的。 (对于最后一个参数是结构但不打算将其用于 kwargs 的情况,是否需要有一种选择加入/退出的方法?有人关心吗?我认为没有人关心do 。)
  • 二进制布局和 C 调用语义等仍然定义良好。
  • 有一天,按类型或数量重载将不再难以实现,除非最终参数的类型不能导致类型重载。 如果发生这些情况,也不应该干扰可变参数参数。
  • 同一组默认值可以在多个函数中重复使用。
  • **kwargs免费:只需创建结构并将其作为位置参数传递。
  • 必需的关键字参数自然是这样的:只是不要在结构中给出默认值,并且您被迫按名称传递 _something_ 。
  • 按名称传递位置参数时不会出现古怪的混淆; 你不能那样做。

缺点:

  • 有点神奇。 但我认为,不过是传递5并从函数的 argspec 推断出类型。
  • 不清楚它如何与现有的do习语互动。 可能很容易说它必须是 _written_ 的最后一个参数,即它仅在与do一起使用时才作为倒数第二个参数起作用。

FWIW int::from_str("4", radix: 10)会与之前提议的使用:作为类型归属运算符发生冲突。

诅咒,被 ASCII 挫败。

int::from_str("4", radix☃ 10)

我会投票支持使用 = 关键字 args,只是不允许 C 在子表达式中赋值的想法..(无论如何,这可能与 rusts 的大多数不可变想法不太吻合).. 我认为 Scala 有这个,对于一个它如何适应类似 c 的语法的可能示例?

有没有地方可以集思广益如何实现其中的任何一个。我想知道变量argumnt 样式是否可以像基于参数计数的函数重载一样在内部实现(几乎就好像参数的数量被后缀到函数名称上一样..)

我们在昨晚的周

我认为每个人都同意函数声明/调用形式的进一步复杂化并不好,并且正如我之前的评论中所建议的

团队还决定以任何方式解决这个问题都不是 1.0 版本的优先事项。 项目负责人@brson建议我们在 1.0 之后(例如,对于 1.1 版本)在此任务上留下任何原型。

因此,这是对所有贡献者的强烈提示:随心所欲地破解,但请在 1.0 版本发布之前不要为此错误提交拉取请求或 r+ 任何内容。

毫无疑问,Rust 是一种了不起的语言。 它做对了很多事情,甚至都不好笑。 但我认为将这个功能推迟到 1.0 版是一个错误。

让我详细说明一下。

对于良好的 API 设计,默认函数参数是 _critical_; 缺少它们会使原本更简单的 API 变得复杂。 标准库中的示例:

和别的。

拥有所有这些可以使用默认参数删除的额外函数名称会不必要地增加认知负担。 用户现在必须知道两个(或更多)名称而不是一个。

如果默认参数被推迟到 1.0 之后,那么由于向后兼容,std 库中的这些函数不能被删除。 这意味着即使将来添加默认参数并且函数的“vanilla”版本现在可以完成其他变体的工作,旧变体仍然存在并且开发人员必须了解它们,因为肯定有人会使用他们,即使只是错误的。

因此,额外的认知负荷将_永远_。

[注意,基于参数类型的函数重载可以进行同样的论证(当前基于 trait 的解决方法太麻烦,std 库函数不使用它),但这个问题不是讨论的地方。]

Rust 开发人员,感谢您在 Rust 上工作并让它变得很棒!

我添加了“遥远的未来”里程碑,以强调我们核心团队希望与任何在这个问题上花一点时间的人交流的极度沮丧。 如果您现在想为 Rust 做出贡献,请解决里程碑 1(明确定义)的 41 个开放错误之一:

https://github.com/mozilla/rust/issues?milestone=12&state=open

或里程碑 2 上的 104 个开放错误之一(向后兼容性):

https://github.com/mozilla/rust/issues?milestone=13&state=open

或者里程碑 3 上的 68 个未解决的错误之一(我们曾经同意的功能对于发布 Rust 1.0 至关重要):

https://github.com/mozilla/rust/issues?milestone=14&state=open

或者甚至只是对这些错误之一发表评论以要求澄清或建议取得进展的方法。 有 213 个错误可供选择; 在这一点上,在其中任何一个上取得进展对 Rust 来说比这个问题更有价值。 任何能够关闭这些错误之一的人都会非常感激。

我可以看到核心团队有更重要的事情要做,但“表达极度沮丧”似乎是一种耻辱:(
+1 到 vallorics 评论。 命名很难,通过文档挖掘和学习更多的名字是令人反感的。 默认参数/重载使它更容易; 使用关键字 args,您将有机会在这方面超越 C++。 (我希望 github 有投票权,我可以点击 +1 而不是在这里咆哮更多,哈哈)

@Valloric我完全同意(正如我之前所说的),并且真的希望

没有一致认为这将是一个很好的语言功能。 也没有针对命名/默认参数制定所有细节的具体建议。 1.0 不会发生这种情况,因为在想出非常不重要的语法糖之前,有一组现有的核心语言功能需要修复或删除。

'dreaming up' 听起来像是天方夜谭,但这些特性已在其他语言中得到证实。 它不仅仅是语法糖 - 它减少了您必须浏览的代码量,减少了您必须学习的符号数量

1.0 不会发生这种情况,因为在想出非常不重要的语法糖之前,有一组现有的核心语言功能需要修复或删除。

我并不是说需要修复/实现的其他语言功能并不重要; 他们可能是。 但它不是要么/要么。 我要说的是,在 1.0 中应该强烈考虑此功能(除了其他功能之外),因为没有它会影响 std 库 _forever_ 中 API 的质量。

这可能是一个有争议的观点,但 IMO 编程语言的生死取决于它们提供的 API,而不是它们中的核心功能。 Python 的“含电池”标准库出售了整个语言。 CPAN 使 Perl 保持活力。 .Net 使编写 C# 代码变得很棒,而 LINQ 是自切片面包以来最好的东西。 C++ 最大的缺点之一是缺乏良好的、标准化的 API。 等等。

API 对于语言的成功至关重要,因此不应将能够创建 _good_ API 的功能作为“非必要的语法糖”丢弃。

@dobkeratops :通过说_做梦_,我试图强调还没有提出完整的建议,所以它不在决策阶段

这种讨论是徒劳的。 为了防止它消耗更多人的时间,我将关闭该问题。 如果有人想在一年后或之后重新打开它(或开始新一期),那也没关系。

如果有人提出几乎所有细节(语法、语义)的提案,我建议将其发布到邮件列表中。 如果就某种方式达成共识是_正确的方式_,那么打开一个问题并将其作为实验性功能实现是有意义的,例如once函数之类的标志。

我第二个@thestinger——如果有人(或一小群人)有一个完整的提案,或者一个有几个清晰拼写的空白点可供讨论的提案,那么由那个人来运行它是合适的通过邮件列表。 这并不能保证我们会实施该提案,但将想法形式化并解释它如何与其他语言功能交互的工作将大大增加该建议的价值。

@thestinger @catamorphism感谢你们保持开放的心态! 当我找到一些时间时,我会准备一份提案并将其发送给 rust-dev。

我创建了一个pad来讨论这个特性并写一个明确的规范: https :

我要重开这个这不是一个优先事项——已经有太多的事情需要完成了——但它是人们想要的一个功能,而且还没有完全排除在外。 我不想关闭有关该主题的任何对话。

@brson谢谢!

我已经用etherpad的链接编辑了原始问题。

你好。
自pad创作以来,它已经完成了许多设计命题,问题,问题等......
所以我创建了第二个板来“总结”讨论板,这个板将用于准确描述功能请求。
垫 URL 在这里: https :

@KokaKiwi现在所有的垫子都是空的。 内容去哪儿了?

@cmr ,我猜:

警告:如果 30 天过去了而没有任何编辑,此垫将被删除。 发生这种情况后无法恢复垫,所以要小心!

:皱眉:

我实际上是在搜索我在 Mozilla Etherpad 实例上创建的垫(为了防止这种情况),但我在我的历史记录中找不到它,我忘了在这里发布链接:(

@cmr @huonw @KokaKiwi ,这是我浏览器历史记录中的两个链接:

https://etherpad.mozilla.org/CQEDa85jLX
https://etherpad.mozilla.org/78FA1bozLd

@dram这就是我要找的! 谢谢:笑脸:
我认为,也许应该使用新链接编辑该问题。

(已编辑。)

除了这是我在投入更多时间使用该语言之前密切关注的事情之一之外,我没有任何有意义的补充。 来自具有此功能的语言(Objective-C 和 Python),我相信命名参数是对生产力的间接主要提升,因为它们如何强制其他人的代码更具可读性。

一个具体的提案应该通过新的 RFC 流程来完成: https :

这里有太多相互矛盾的想法和分歧的话题,因此它不能成为一个有用的讨论领域。

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