向Rust学习Go考虑简单字符串插值特性示例解析

目录
  • fmt.Printf 或 fmt.Sprintf 写拼装字符串业务
  • 简单字符串插值
  • 其他语言例子
    • Swift
    • Kotlin
    • C
    • Rust
  • 争论矛盾点
  • 总结

fmt.Printf 或 fmt.Sprintf 写拼装字符串业务

在日常开发 Go 工程中,我们经常会用 fmt.Printf 或 fmt.Sprintf 去写类似的拼装字符串的业务。

如下代码:

fmt.Printf("Hello Gopher %s, you are %d years old and you're favorite food is %s", name, age, favoriteFood)

这业务迭代迭代着,日积月累的,有一部分常变的拼装逻辑会来越长。小小的电脑显示屏已经不足以让代码在一行内显示了。

有许多特性会把字符串转为变量,但后面那串又臭又长的变量依然无法简单甩掉,因此有大部分同学会选择把代码格式化了。

如下代码:

s :=  "Hello Gopher %s, you are %d years old and you're favorite food is %s"
fmt.Printf(
    s,
    name,
    age,
    favoriteFood,
)

你可能以为这是个例?实际并不,很多人都遇到了。

简单字符串插值

这在 Go issues 中社区讨论了三四年了,@Ian Lance Taylor 发起了新提案《proposal: spec: add simple string interpolation similar to Swift》。

希望能够得到更多的讨论,增加新特性解决这个问题。

这个新特性,类似于 Swift 中的字符串插值的简单版本。我们直接看例子:

fmt.Println("\(person.Name()) is \(person.Age()) years old")
fmt.Println("The time is \(time.Now().Round(0))")

对应的输出结果:

Ken Thompson is 79 years old

The time is 2023-01-04 16:22:01.204034106 -0800 PST

提案计划新增的 “字符串插值”,规范如下:

  • 新转义语法:\(xxxx),开头是 \(,结尾是 ),成对出现。
  • 在格式上,一个有效的 \(,后面必须有一个表达式和一个尾部的 ,这样才能生效。

上面的例子中,以下几个都是字符串插值:

\(person.Name())
\(person.Age())
\(time.Now().Round(0))

会有同学疑惑像 person 看起来就是结构体的是怎么取值的?

Go 有一个神奇的约定方法,像结构体这类类型,如果有 String() string 方法,将会调用该方法以获取字符串值。

如果没有 String 方法,需要是字符串、整数、浮点数、复数、常量或布尔值等类型,可以取值后格式化。否则将会报错。

其他语言例子

Swift

let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"

Kotlin

var age = 21
println("My Age Is: $age")

C

string name = "Mark";
var date = DateTime.Now;
Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now.");

Rust

let person = get_person();
println!("Hello, {person}!"); // captures the local `person`
println!("Hello, {}!", get_person());                // implicit position
println!("Hello, {0}!", get_person());               // explicit index
println!("Hello, {person}!", person = get_person()); // named
let (width, precision) = get_format();
for (name, score) in get_scores() {
  println!("{name}: {score:width$.precision$}");
}

争论矛盾点

当前的主要争论点之一,像是 fmt.Sprintf 等方法也可以完成字符串插值一模一样的效果,为什么还要新增这个功能特性(或是语法糖)?

主流观点是现有的格式化字符串的方法,在参数数量多了后,很容易出错(例如:顺序搞错),也比较松散,一大坨代码。

在新增字符串插值的特性/语法糖后,可以更好阅读、更好修改,不需要过于依赖编写变量的顺序、更紧凑。

具体的例子如下,现有版本代码:

errorf(pos, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst.elem, src.elem)

应用新特性后会变成:

error(pos, "arguments to copy \(x) and \(&y) have different element types \(dst.elem) and \(src.elem)")

总结

其实我们在工作中都经常遇到这个问题,甚至在 issues 中有同学反馈,他经常要写 50 个以上参数的格式化参数,在 Go 这维护起来比较痛苦。

如果你是长期维护某几个项目的开发者,不断持续新增、变更的现有格式化字符串的方法,和新增的字符串插值。

在接下来的几年中,你会选择哪一个?或是有没有新的想法?

以上就是向Rust学习Go考虑简单字符串插值特性示例解析的详细内容,更多关于Rust Go简单字符串插值的资料请关注我们其它相关文章!

(0)

相关推荐

  • Go调用Rust方法及外部函数接口前置

    前言 近期 Rust 社区/团队有些变动,所以再一次将 Rust 拉到大多数人眼前. 我最近看到很多小伙伴说的话: Rust 还值得学吗?社区是不是不稳定呀 Rust 和 Go 哪个好? Rust 还值得学吗? 这些问题如果有人来问我,那我的回答是: 小孩子才做选择,我都要! 当然,关于 Rust 和 Go 的问题也不算新,比如之前的一条推文: 我在本篇中就来介绍下如何用 Go 调用 Rust. 当然,这篇中我基本上不会去比较 Go 和 Rust 的功能,或者这种方式的性能之类的,Just fo

  • Rust中的Cargo构建、运行、调试

    目录 基本概念 Cargo相关命令 创建工程目录说明 VSCode 中配置 Rust工程 基本概念 Cargo是rustup安装后自带的,Cargo 是 Rust 的构建系统和包管理器.Rust 开发者常用 Cargo 来管理 Rust 工程和获取工程所依赖的库.入门教程中使用 cargo new helloworld 命令创建了一个名为 helloworld 的工程,Cargo 新建了一个名为 helloworld 的文件夹并在里面部署了一个 Rust 工程最典型的文件结构.这个 hellow

  • 使用Cargo工具高效创建Rust项目

    目录 前言 一.功能强大的Cargo工具 1.Cargo工具是什么? 2.使用Cargo命令创建 hello_cargo 项目 3.项目文件目录里各文件的内容和特点 4.Cargo 常用命令 二.Rust 语言的输入输出 1.输入输出测试 2.具体代码解析 前言 本文紧跟上篇Rust博文内容,讲解Cargo工具在Rust项目创建时的妙用,手把手教你使用Cargo工具在黑窗口创建项目.此外,创建项目之后,简单的做一个Rust语言中输入输出的测试,上文提到学好Rust语言的方法就是一步一步打基础,因

  • Rust中Cargo的使用详解

    目录 1.cargo简介 2.使用cargo创建项目 2.1.关于Cargo.toml 2.2 .关于src/main.rs 3.构建Cargo项目 4.构建并运行Cargo项目 5.检查代码是否可编译 6.发布(release)构建 7.把Cargo当作习惯 8.总结 1.cargo简介 Cargo 是 Rust 的构建系统和包管理器.⼤多数 Rustacean 们使⽤ Cargo 来管理他们的 Rust 项⽬,因为它可以为你处理很多任务,⽐如构建代码.下载依赖库并编译这些库.(我们把代码所需

  • 向Rust学习Go考虑简单字符串插值特性示例解析

    目录 fmt.Printf 或 fmt.Sprintf 写拼装字符串业务 简单字符串插值 其他语言例子 Swift Kotlin C Rust 争论矛盾点 总结 fmt.Printf 或 fmt.Sprintf 写拼装字符串业务 在日常开发 Go 工程中,我们经常会用 fmt.Printf 或 fmt.Sprintf 去写类似的拼装字符串的业务. 如下代码: fmt.Printf("Hello Gopher %s, you are %d years old and you're favorite

  • PHP简单字符串过滤方法示例

    本文实例讲述了PHP简单字符串过滤方法.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-s

  • Java实现的简单字符串反转操作示例

    本文实例讲述了Java实现的简单字符串反转操作.分享给大家供大家参考,具体如下: 最常用的方式是,反向取出每个字符,然后打印: public class StringReverse { public static void main(String[] args) { // 原始字符串 String s = "A quick brown fox jumps over the lazy dog."; System.out.println("原始的字符串:" + s);

  • java学习笔记_关于字符串概述

    一.String类 String类代表字符串,是由字符构成的一个序列.创建String对象的方法很简单,有以下几种: 1)用new来创建: String s1 = new String("my name is tongye"); 2) 不用new直接创建: String s2 = "my name is tongye"; 3) 可以用字符数组来创建一个字符串: char[] c = {'t','o','n','g','y','e'}; String s3 = new

  • Pinia入门学习之实现简单的用户状态管理

    目录 Store是什么? Store的应用场景? pinia是什么? 其他优点 应用示例 定义Store 使用Store 获取store的响应式数据 State 初始化 读取和写入state 订阅state变化 Getters 定义getter 访问getter Actions 定义action 订阅action 总结 Store是什么? 全局状态,用于在所有组件中,同步数据. Store的应用场景? 在整个应用程序中访问的数据(且不需要被持久化),例如导航栏中显示的用户信息,以及需要通过页面保

  • js 正则学习小记之匹配字符串字面量优化篇

    昨天在<js 正则学习小记之匹配字符串字面量>谈到 /"(?:\\.|[^"])*"/ 是个不错的表达式,因为可以满足我们的要求,所以这个表达式可用,但不一定是最好的. 从性能上来说,他非常糟糕,为什么这么说呢,因为 传统型NFA引擎 遇到分支是从左往右匹配的, 所以它会用 \\. 去匹配每一个字符,发现不对后才用 [^"] 去匹配. 比如这样一个字符串: "123456\'78\"90" 共 16 个字符,除了第一个 &q

  • java初学者如何让编程学习起来更简单

    如果不喜欢学Java就不要学了,硬要逼着自己去学到头来也会是一知半解.不仅浪费时间,也浪费金钱,如果喜欢Java那就继续学,并且努力学,学好Java会有意想不到的好处.学习Java会有一个很艰难的过渡期,在此期间你要努力学好它并度过它,那么你就成功了.学任何东西,入门的时候,觉得难或者吃力是很正常的事情,小学生学习个加减乘除不也花了三四年的时间吗? 行百里者半九十,从0到1是最艰难最吃力的一步,先慢后快,怕的是中途放弃.而你当年读小学的时候却不会- 1.很多人还没学习JAVA就开始觉得java很

  • GO语言入门学习之基本数据类型字符串

    目录 字符串 字符串转义符 byte和rune类型 修改字符串 类型转换 总结 字符串 Go语言中的字符串以原生数据类型出现. Go 语言里的字符串的内部实现使用UTF-8编码. 字符串的值为双引号(")中的内容,可以在Go语言的源码中直接添加非ASCII码字符 GO语言中字符串是用双引号包裹的 GO语言中单引号包裹的是字符 // 字符串 s := "Hello 中国" // 单独的字母.汉字.符合表示一个字符 c1 := 'h' c2 := '1' c3 := '中' //

  • C++学习贝叶斯分类器实现手写数字识别示例解析

    大家好啊!这次的文章是上一个文章的后续,与上一次不同的是,这一次对数字识别采用的是贝叶斯(Bayes)分类器.贝叶斯在概率论与数理统计这门课讲过,下面我们简单了解一下: 首先,贝叶斯公式是 具体的解释就不说了,我们说一说把贝叶斯用在数字识别的什么位置.除了识别部分,其他的包括遍历文件夹和图片数字化都不变:0到9共十个数,所以分母有十项,P(Bj)(j是下标)相应的是0到9,则每一个的概率是1/10,分子上的P(Bi)是取到0到9中的一个,所以概率也是1/10. (小伙伴如果看不明白建议去看看贝叶

  • 学习JSON.stringify的9大特性和转换规则

    目录 一.JSON.stringify介绍 二.9大特性要记住 特性一 特性二 特性三 特性四 特性五 特性六 特性七 特性八 特性九 三.手写一个JSON.stringify 一.JSON.stringify介绍 JSON.stringify()  方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性. 语法: JSON.stringify(val

随机推荐