Go Wiki:Go 2 泛型反馈
此页面旨在收集和整理有关 Go 2 合同(泛型)草案设计 的反馈。
可以在 https://golang.ac.cn/cl/149638 中找到语法原型实现,该实现可能会修补在 Go 存储库提示上。
请在您的博客、Medium、GitHub Gists、邮件列表、Google Docs 等上发布反馈。然后请在此处链接它。
随着反馈数量的增加,请随时按特定类型的反馈组织或重新组织此页面。
支持
-
Roger Peppe,“Go 合同用例:通用 mgo”,2018 年 9 月
-
Richard Fliam,“Go2 泛型让您构建自然数”,2018 年 8 月
补充(支持修改)
-
马特·麦卡洛,“走向清晰:Go 中合约的语法更改”和“Go 合约的角度括号分隔符”,2020 年 5 月
-
格特·库肯斯,“泛型语法形式与常规 Go 代码的完全分离”,2020 年 1 月
-
科特·福勒,“一位懒惰程序员对更新设计的思考”,2019 年 9 月
-
安德鲁·菲利普斯,“示例类型作为合约”,2019 年 8 月
-
阿列克谢·涅兹达诺夫,“语法简化建议”,2019 年 8 月
-
布莱恩·福特,“对于 Go 2 泛型来说,只有类型参数才足够泛型吗?”,2019 年 7 月
-
汤姆·利维,“Go 2 泛型反馈”,2019 年 6 月
-
奥莱·布尔布克,“鉴于不断变化的 Go 社区,为什么 Go 合约是一个糟糕的主意”,2019 年 4 月
-
托尼·莫塔兹,“Go 泛型类型和导入注入”,2019 年 3 月
-
古斯塔沃·比滕科特,“仅适用于泛型类型的合约”,2019 年 3 月
-
戴维·霍伊施曼,“使用圆括号表示类型参数列表的问题”,2019 年 2 月
-
古斯塔沃·比滕科特,“带有方法的合约”,2019 年 2 月
-
克里斯·西本曼,“Go 2 泛型:合约过于巧妙”,2018 年 11 月
-
克里斯·西本曼,“Go 2 泛型:一种让人们更容易阅读合约的方法”,2018 年 11 月
-
克里斯·西本曼,“Go 2 泛型:接口不是类型约束的正确模型”,2018 年 11 月
-
alanfo,“根据收到的反馈,对 Go 草案泛型设计提出的更改”,2018 年 10 月
-
安迪·巴尔霍姆,“枚举和结构合约”,2018 年 10 月
-
布拉克·塞尔达尔,“类型是合约”,2018 年 10 月
-
帕特里克·史密斯,“Go 泛型用于内置和用户定义的类型参数”,2018 年 9 月
-
雅各布·卡尔博格,“Go 2 草案 D 更正”,2018 年 9 月
-
alanfo,“简化的泛型约束系统”,2018 年 9 月
-
Paul Borman,“简化语法”,2018 年 9 月
-
mrwhythat,“Go 2 泛型草案说明”,2018 年 9 月
-
Roger Peppe,“运算符重载”,2018 年 9 月
-
Peter McKenzie,“备选泛型语法”,2018 年 9 月
-
Ted Singer,“语法的设计目标是帮助人类阅读”,2018 年 9 月
-
alanfo,“建议对 Go 2 泛型草案设计进行修正”,2018 年 9 月
-
Dean Bassett,“如果我们要使用契约,则允许对字符串使用一元 +”,2018 年 9 月
-
Kevin Gillette,“关于 Go 2 泛型草案”,2018 年 9 月
-
jimmy frasche,“不允许嵌入类型参数”,2018 年 8 月
-
Javier Zunzunegui,“编译泛型”,2018 年 8 月
-
Liam Breck,“请不要破坏函数签名”,2018 年 8 月
-
DeedleFake,“对 Go 2 设计草案的反馈”,2018 年 8 月
-
Roberto (empijei) Clapis,“难以阅读的语法”,2018 年 8 月
-
Dominik Honnef,“我对 Go 泛型草案的看法”,2018 年 8 月
反建议
-
dotaheor,“将泛型声明为具有泛型参数的迷你包”,2020 年 8 月
-
Beoran,“卫生宏”,2019 年 6 月
-
Randy O’Reilly,“泛型原生类型”,2019 年 6 月
-
Michal Štrba,“放弃限制类型”,2019 年 5 月
-
Eric Miller,“使用常量结构字段的简单泛型”,2019 年 3 月
-
dotaheor,“统一 Go 内置泛型和自定义泛型的解决方案”,2019 年 2 月
-
昆汀·夸德格拉斯,无语法更改,1 个新类型,1 个新内置,2018 年 12 月
-
安迪·巴尔霍姆,“契约和适配器”,2018 年 11 月
-
迪安·巴塞特,“契约嵌入”,2018 年 10 月
-
帕特里克·史密斯,“使用适配器的 Go 泛型”,2018 年 10 月
-
伊恩·登哈特,“Go 泛型:具体提案重新使用接口而不是契约。”,2018 年 10 月
-
Arendtio “受接口启发的 Go 中的泛型”,2018 年 9 月
-
斯科特·科顿,“统一契约和接口的提案修改草案” (diff),2018 年 9 月
-
ohir,“CGG,工匠 Go 泛型”,2018 年 9 月
-
~~迪安·巴塞特,“使用接口而不是契约”,2018 年 9 月~~
我提出了另一个提案(“契约嵌入”),列在下面,该提案解决了此提案中的问题 -
dotaheor,“将契约和代码结合在一起,并将泛型视为具有多个输出的编译时调用”,2018 年 9 月。(不时更新)
-
阿列克谢·帕夫柳科夫,“扩展类型和函数关键字”,2018 年 9 月
-
韩拓,“泛型作为一种类型 - 类型 T 泛型 {int, float64}”,2018 年 9 月
-
内特·芬奇,“Go2 契约走得太远”,2018 年 9 月
-
罗杰·佩佩,“Go 契约作为类型结构”,2018 年 9 月
-
阿克塞尔·瓦格纳,“废弃契约”,2018 年 9 月
-
马特·谢尔曼“泛型作为内置类型类”,2018 年 9 月
-
罗杰·佩佩,“修订后的泛型提案”,2018 年 9 月
-
史蒂文·布伦金索普,“对 Go2 合同草案设计——辅助类型的回应”,2018 年 9 月
-
戴夫·切尼,“也许向 Go 中添加泛型最终还是关于语法”,2018 年 9 月
-
克里斯蒂安·苏尔利克,“Go 泛型的约束,2018 年 9 月”
-
go-nuts 上的一些 Gophers,“统一接口和合同”,2018 年 8 月
-
罗杰·佩佩,“Go 泛型反馈,2018 年 8 月
-
阮昆良,“包级泛型”,2018 年 8 月
-
艾米丽·迈尔,“具体了解泛型”,2018 年 8 月
反对
- 东京 Gophers,“Go 2 草案设计反馈活动评论”,2018 年 10 月
-
杰森·莫伊伦,“关于 Go2 泛型草案的说明”,2018 年 9 月
-
涩川芳树,“对泛型/合同提案的反馈,2018 年 9 月”
添加您的反馈
请按以下格式设置所有条目。
- 您的姓名,“标题”,年月
为了更容易查看新反馈。请创建一个 Gist。还要帮助按时间倒序列出列表,方法是将您的新条目包含在类别列表的顶部。
快速评论
-
Chester Gould:此提案的唯一问题在于显式契约似乎只会让代码更加冗长,这与简洁可读代码的目标背道而驰。与其编写显式契约,不如将我们编写的实际代码用作某种“隐式契约”,这将更加简单优雅。此示例显示在此处。我承认已在此处解决了此问题,但我不同意显式契约是解决此问题的方案。在我看来,契约与接口提供的功能非常接近,因此应该扩展接口的行为以允许行为更接近契约,而不是向语言中添加一个全新的语句类型。
-
Izaak Weiss:很多讨论都集中在如何具体实现契约或类似内容上。然而,大多数“有用的示例”并不需要契约;它们只需要参数多态性。编写类型安全的
Merge
或SortSlice
无需契约。对于更简单的契约,我们可以通过高阶函数实现它们。泛型哈希映射可以针对具有Hash
方法的类型进行参数化,或者在构建时可以采用func(K) int64
,并使用它对键进行哈希处理。如果需要更多函数,则可以将保存这些函数的结构声明为伪契约,然后可以将它们传递给泛型函数。这使得 Go 的多态性变得简单、显式,并为未来有关契约或其他机制的进一步创新留出了空间,同时允许立即实现泛型类型的大部分好处。 -
Christoph Hack:我刚刚观看了 Alexandrescu 的最新演讲 The next big Thing。他表示“概念是浪费时间”,并提出了一个完全不同的、更强大的方向(甚至与当今 C++ 中所有可能的方向相比)。Go 已经具备大多数必需的功能,例如反射和测试类型是否实现了可选接口。唯一缺少的是代码生成。例如,
json.Marshal
通过使用反射工作得很好,但如果它还可以(可选地)通过实现一个由编译器自动调用并运行常规 Go 代码的 Go 函数来生成代码,那么我们就会拥有所有内容。乍一听起来可能很疯狂,玩具示例可能看起来很冗长,但我认为 Alexandrescu 在这一点上是有道理的。例如,想想 gqlgen 与其他基于反射的 graphql 库。请观看他的演讲! -
Bodie Solomon:我发现泛型设计有点混乱和不透明。请考虑整合一些来自 Zig 的漂亮的编译时函数 的概念!Go 2 泛型的设计很巧妙,但我感觉它违背了 Go 在简单的运行时语义和简单的语法之间的传统紧密耦合。此外,Go 最大的问题之一是它无法摆脱 GC 和运行时,这阻止了它成为我在任何可能使用它的领域中的可行竞争对手。我强烈希望 Go 2 引入仅限编译时的泛型,以便我可以在不需要动态接口的地方可靠地避免使用它们,而无需依赖代码生成。不幸的是,看起来这将由编译器决定,而不需要我的输入。请至少考虑赋予用户将泛型限制为仅限编译时解析的能力,或许作为契约的属性,拒绝编译动态类型以满足契约。
-
Dag Sverre Seljebotn:C++ 存在一个大问题,即人们滥用元编程(“泛型”)来进行编译时元编程。我真希望 Go 能够沿着 Julia 的道路发展,后者提供了卫生的宏。即使它被严格地保留在编译时障碍上,并且没有运行时代码生成,这也至少可以避免我们在 C++ 世界中看到的由于其模板系统而产生的所有不良倾向。你可以用泛型做的事情通常也可以用宏来完成(例如,
SortSliceOfInts = MakeSliceSorterFunctionMacro!(int)
可以生成一个新函数来对整数切片进行排序)。链接:https://docs.julia-lang.cn/en/v0.6.1/manual/metaprogramming/ -
Maxwell Corbin:讨论和开放问题部分提出的问题都可以通过在包而不是函数或类型级别定义泛型来避免。原因很简单:类型可以引用它们自己,但包不能导入它们自己,并且虽然有许多方法可以算法生成更多类型签名,但你不能对导入语句执行相同的操作。此类语法的快速示例可能是
\\ list package list[T] type T interface{} type List struct { Val T Next *List } // main package main import ( il "list"[int] sl "list"[string] ) var iList = il.List{3} var sList = sl.List{"hello"} // etc...
示例中的语法可能不必要地冗长,但重点是博客文章中没有任何不幸的代码示例甚至是合法的构造。包级别泛型避免了元编程最严重的滥用问题,同时保留了其大部分实用性。
-
Andrew Gwozdziewycz:由于它将“contract”重载为契约设计中的“contract”,因此使用
contract
一词让我停顿下来。虽然泛型用例与 DbC 中的“contract”有一些相似之处,如果你眯着眼睛看的话,但这些概念是截然不同的。由于“contract”是计算机科学中一个既定的概念,我认为使用behavior
或trait
等其他名称会减少很多困惑。设计文档还提出了不使用interface
的理想原因,不过,Go 的 contract 机制似乎是接口的一个过于明显的扩展,不能这么快就忽略它……如果可以这样做,interface setter(x T) { x.Set(string) error }
和interface addable(x T, y U) { x + y }
似乎很容易阅读和理解。- Russell Johnston:同意将 contract 和接口合并起来会很棒。解决运算符命名问题的另一种方法可能是为运算符提供一些标准接口,其主体无法用普通的 Go 代码表示。例如,一个标准的
Multipliable
接口将允许使用*
和*=
运算符,而一个标准的Comparable
接口将允许使用==
、!=
、<
、<=
、>=
和>
。为了表示具有多个类型的运算符,这些接口可能需要类型参数本身,例如:type Multipliable(s Self /* 这存在于所有接口中 */, t Other) interface { /* 由语言提供 */ }
。然后,用户编写的接口/contract 可以使用这些基于标识符的标准名称,巧妙地避开设计文档中提到的有关语法和类型的相关问题。 - Roberto (empijei) Clapis:我同意这一点,也同意应该更清楚地在何处使用接口以及在何处使用 contract。统一两者会很棒,因为它们试图解决重叠的问题。
- Kurnia D Win:我认为
constraint
是比contract
更好的关键字。就我个人而言,我更喜欢type addable constraint(x T, y U) { x + y }
,而不是与接口合并。
- Russell Johnston:同意将 contract 和接口合并起来会很棒。解决运算符命名问题的另一种方法可能是为运算符提供一些标准接口,其主体无法用普通的 Go 代码表示。例如,一个标准的
-
Hajime Hoshi:我觉得提议的方案对于我们要解决的问题来说过于庞大,这些问题已列在 https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md 中。我担心此功能会被滥用,并降低代码的可读性。抱歉,如果我理解有误,但该提案并未提及
go generate
。难道go generate
不足以解决这些问题吗? -
Stephen Rowles:我发现方法语法难以解析,作为阅读该语法的人,使用不同类型的括号来括起类型部分可能会更清晰,例如:我也赞成 👍 +1。又一个 👍 +1(Pasha Osipyants)。
func Sum<type T Addable>(x []T) T { var total T for _, v := range x { total += v } return total }
-
yesuu:在此示例中,将
T
视为参数名称,将type
视为参数类型。显然,将type
放在后面更合理,并且 contract 后面跟着type
,例如chan int
。func Sum(T type Addable)(x []T) T
-
Seebs:反馈有点长,无法内联,2018 年 8 月。总结基本上是“我希望有一种方法为两种类型中的每一种指定一个契约,而不是为两种类型指定一个契约”,以及“我更喜欢
map[T1]T2
而不是t1var == t1var
作为“T1 必须是允许的地图键”的规范形式。 -
Seebs:如果协定只是类型参数化函数会怎样?(2018 年 9 月 1 日)
-
Sean Quinlan:我发现协定语法相当令人困惑。对于一个应该明确定义所需内容并成为 API 文档一部分的东西,它可能包含各种各样的无关内容,这些内容不会影响协定。此外,引用设计中的内容:“我们不必解释协定正文中可能出现的每条语句的含义”。这似乎与我对协定的期望相反。在我看来,可以将函数正文复制到协定中并使其正常工作似乎是一个错误,而不是一个特性。就我个人而言,我更喜欢统一接口和协定的模型。接口感觉更接近于我希望协定看起来的样子,并且有很多重叠。许多协定似乎也将成为接口?
-
Nodir Turakulov:请详细说明
诸如 container/list 和 container/ring 之类的包以及诸如 sync.Map 之类的类型将更新为编译时类型安全。
并且
math 包将得到扩展,为所有数字类型提供一组简单的标准算法,例如广受欢迎的 Min 和 Max 函数。
或者理想情况下,添加一个关于现有类型/函数使用类型多态性的转换/迁移的部分。FWIU 向现有类型/函数添加类型参数很可能会破坏使用该类型/函数的现有程序。
math.Max
将如何具体更改?目的是进行向后不兼容的更改并编写工具以自动将代码转换为 Go2 吗?对于提供目前使用interface{}
运行的函数和类型的其他库的作者,有什么一般建议?是否考虑了类型参数的默认值?例如,math.Max
的类型参数将默认为float64
,而"container/list".List
的类型参数将默认为interface{}
-
Ward Harold:仅仅为了完整性,Modula-3 泛型设计应纳入其他语言中的设计部分。Modula-3 是一种美丽的语言,遗憾的是在错误的时间被引入。
- 马特·霍利迪:同样提到 Alphard 语言,它与 CLU 同时开发,也影响了 Ada 设计。请参阅玛丽·肖编辑的《Alphard:形式与内容》,施普林格 1991 年,了解收集的各种论文以及一些粘合材料。Alphard 和 Ada 是我接触泛型编程的开端。经过 40 年的等待,Go 能否击败 C++,最终实现合约?
-
奥勒·贝格曼:您在 泛型概述页面 上写道:“Swift 在 2017 年发布的 Swift 4 中添加了泛型。”这是不正确的。Swift 自 2014 年首次公开发布以来就有了泛型。证据(仅举一例):苹果开发者在 WWDC 2014 上关于 Swift 的演讲记录,其中详细介绍了 Swift 的泛型功能。
这也是不正确的:“
Equatable
似乎是 Swift 中的内置函数,无法以其他方式定义。”Equatable
协议在 Swift 标准库中定义,但它没有任何特殊之处。完全可以在“普通”代码中定义相同的内容。 -
凯文·吉列特:截至 2018 年 8 月 30 日,“合约”草案的更正
check.Convert(int, interface{})(0, 0)
的一个实例应改为check.Convert(int, interface{})(0)
,或提供解释,说明为什么该函数应使用两个零而不是一个零。 -
亚当·伊里门科:我有一个在 Go 中进行有限运算符重载的想法,这可能会让此提案对数字代码更有用。它很大,所以我 把它放在了 Gist 中。
- DeedleFake:我完全同意反对运算符重载的论点,我很高兴 Go 整体上没有它,但我也认为无法通过合约解决
a == b
和a.Equals(b)
之间的差异是当前草案设计中最大的问题。这意味着你仍然需要为相当多的东西编写多个函数。例如,尝试编写一个二叉树。你应该使用t < t
还是t.Less(t)
的合约?对于求和函数,你应该使用t + t
还是t.Plus(t)
?不过,我绝对想要一种不涉及运算符重载的解决方案。也许可以指定一个适配器,它基本上说如果类型 T 满足合约 A 但不满足合约 B,则将其用于受合约 B 约束的参数,对其应用此适配器以使其满足合约 B
。例如,合约 B 可能需要一个Plus()
方法,而合约 A 需要使用+
,因此适配器会自动将用户指定的Plus()
方法附加到T
,以便在该合约下使用它。- 可以使用此提案的可能是
equal(a, b)
内置,如果存在a.Equals(b)
,则使用它,否则使用a == b
,如果类型不可比较,则编译失败(对于其他运算符也是如此)。这太奇怪了,无法认真考虑,但它适用于契约,并且允许避开具有运算符和不具有运算符的类型之间的不对称,而无需引入运算符重载 —jimmyfrasche - 另一个想法是显式可重载运算符:
a + b
不可重载,但a [+] b
可重载。它将对基本类型使用普通 +,但如果存在,它将对对象使用Operator+()
等。我确实认为,如果没有某种明智形式的运算符重载或类似形式,泛型对您来说用处不大,以至于您甚至不必这样做。-Adam Ierymenko(原帖)
- 可以使用此提案的可能是
- Ian Denhardt:DeedleFake 概述了没有运算符重载的问题,我认为涉及使重载“响亮”的提案是错误的想法;相反,我们应该限制哪些运算符可以重载为满足这些条件的运算符
- 运算符的语义可以理解为方法调用。数字上的大多数运算符都通过了此测试;
big.Add
仍然是加法,因为我们从 int32、uint64 等中了解到它。未通过此测试的运算符示例包括&&
和||
;这些是短路,没有函数或方法可以复制。无论如何看待它们,它们从根本上都不是方法,并且不应该被方法覆盖。我认为运算符重载之所以名声不好,部分原因是 C++ 允许您覆盖所有内容,包括逗号运算符等疯狂的东西。 - 应该有明确的用例来覆盖它们。同样,算术运算符通过此测试,以及
<
和朋友。指针取消引用通过第一个测试,但我很难想出实际上看起来像好主意的“其他类型的指针”的用途。它们在 C++ 中更合理,但垃圾回收指针基本上已经涵盖了您。 - 运算符的正常含义应该是易于理解的。例如,指针是错误的根源,并且具有
*foo
可能执行除从内存地址读取之外的其他操作的可能性,这使得本已困难的调试会话变得更加困难。另一方面,+
可能调用big.Add
的可能性是相对独立的,并且不太可能造成很大的混乱。 - 最后,标准库必须树立一个好榜样;例如,覆盖
+
的方法在概念上应该是加法。C++ 在这里走了一条完全错误的道路,定义了在道德上os.Stdout.ShiftLeft("Hello, World!")
的内容。
- 运算符的语义可以理解为方法调用。数字上的大多数运算符都通过了此测试;
- DeedleFake:我完全同意反对运算符重载的论点,我很高兴 Go 整体上没有它,但我也认为无法通过合约解决
-
Eltjon Metko:如何在函数参数中的类型标识符后面指定契约?这样可以推断出 T 是什么,并且我们可以消除第一组括号。
func Sum(x []T:Addable) T { var total T for _, v := range x { total += v } return total }
-
Tristan Colgate-McFarlane:经过一番来回之后,我赞成该提案,因为它在很大程度上是原样。契约的有限语法可能更可取,但我认为它应该允许引用特定字段(而不仅仅是一些人建议的方法)。如果可以采取任何措施使兼容的接口和契约更容易相互使用,那将很好(尽管我认为可能不需要其他规范。最后,我认为值得考虑弃用接口类型。虽然激进,但契约本质上也允许指定行为。任何限制该行为的契约限制(例如引用包中的其他类型)都应该解除。契约似乎是接口的严格超集,我通常反对同时拥有两个重叠特性。还应该考虑一个帮助编写接口的工具。
-
Patrick Smith:在为泛型类型定义方法时,我们可能需要考虑要求使用类型关键字。这使得代码更加冗长,但更清晰、更一致(现在类型参数始终以类型关键字开头)。
func (x Foo(type T)) Bar()
-
Patrick Smith:在此示例中,
Foo(T)
是否嵌入在Bar(T)
中,还是Bar(T)
有一个名为Foo
的方法?type Foo(type T) interface {} type Bar(type T) interface { Foo(T) }
-
Xingtao Zhao:该提案中有太多圆括号。该提案中称,“[]” 在某些情况下是模棱两可的。而如果我们使用 [type T, S contract],则不再有任何歧义。
-
Dave Cheney:早期的类型函数提案表明类型声明可以支持参数。如果这是正确的,那么可以从以下内容中重新编写提议的契约声明
contract stringer(x T) { var s string = x.String() }
到
type stringer(x T) contract { var s string = x.String() }
这支持了 Roger 的观察,即合约是接口的超集。
type stringer(x T) contract { ... }
以type stringer interface { ... }
引入新接口类型的方式引入了新合约类型。- jimmyfrasche:不过,合约不是类型。你不能拥有一个值为
stringer
的值。你可以拥有一个值为stringer
的类型的类型。它是一种元类型。类型是对值的某种谓词。你询问编译器“这个值是否为string
”,它会回答是(允许编译继续)或否(停止并告诉你出了什么问题)。合约是对类型向量的谓词。你向编译器提出两个问题。这些类型是否满足此合约?然后:这些值是否满足这些类型?接口通过存储(type, value)
对(前提是该类型具有适当的方法)来模糊这些界限。它同时是类型和元类型。任何不使用接口作为元类型的泛型系统都不可避免地包含接口的超集。虽然完全有可能定义一个专门使用接口作为元类型的泛型系统,但这意味着失去编写使用接口无法讨论的事物的泛型函数的能力,例如运算符。你必须将你可以询问类型的问题限制在其方法集上。(我对此很满意)。
- jimmyfrasche:不过,合约不是类型。你不能拥有一个值为
-
btj:设计文档草案的其他语言部分中缺少两个非常重要的条目:具有类型类的 Haskell 和具有隐式参数的 Scala。
-
iamgoroot:对类型别名支持进行更好的支持并让用户选择泛型不是更自然吗?而且你不需要太多语法
type Key _
type Value _
type IntStringHolder Holder<Key:int, Value:string>
type Holder struct {
K Key
V Value
}
func (h *Holder) Set(k Key, v Value) {
h.K = k
h.V = v
}
func main() {
v:= IntStringHolder{}
v.Set(7,"Lucky")
}
-
antoniomo:虽然草案清楚地解释了为什么
F<T>
、F[T]
和非 ASCII(无法在此处键入)F<<T>>
被丢弃,但感觉F{T}
比有时连续三个()
更易于阅读,同时不会通过无界向前查找使解析器复杂化,因为在这种情况下你无法打开块。 -
aprice2704:我真的很不喜欢使用常规括号
(
的想法,两字符序列会因无界向前查找而导致编译器开销吗?<|
和|>
怎么样?它们会起作用吗?它们具有与(
完全不同的优点,在 ascii 中具有一定的视觉意义,并且在我用于 VSCode 的“Fira Code”字体(强烈推荐)中,有连字将它们呈现为指向左右的小三角形。 -
leaxoy:首先,我为编辑页面页脚感到抱歉,但我无法删除页脚内容。这是我的看法:大量的
(
和)
使 Go 看起来很混乱,<
和>
就像其他语言一样更好,并且对那些来自其他语言的人来说更友好。 -
Hajime Hoshi:我完全同意 aprice2704 对语法提出的问题。例如,
[[
/]]
无法正常工作吗?
此内容是 Go Wiki 的一部分。