A better C:from C++, Go,Rust to Zig

从C语言诞生已经五十多年了,现在已经有了许多高级语言,其中很多背靠大厂,比如Java,Go,C#,Dart,Swift等等(甲骨文,谷歌微软和苹果,这类语言通过公司更新).也有很多社区的语言,比如Python,Rust,PHP,Ruby等(这类语言往往通过早期创建者和一些核心成员更新和维护,这里面也有很多开源的语言,允许其他人修改).
相较于公司旗下的语言,社区类型的语言往往更加简洁,在使用或者生产下效率高,但也存在生态相对较差、工具链不够、更新发力不够持久、文档不够丰富的问题.

而 A better C的意思就是在后面的语言中找到性能较强,使用友好并且生态持续发展的语言.TLDR:在大型项目上还是使用C++,在一些工具链或者代码重构上可以考虑Rust.

“世上其实只有两种编程语言,一种是大家一直喷它难用的,一种是根本没人用的。” —— C++ 的作者 Bjarne Stroustrup

相对于Java,C#这种语言,我们尝试找到使用上更加轻型(指的是不依赖某种领域),性能更强占用更小的语言.

Better C

C++

C++20目前已经有了很多Modern的特性,但是目前仍然缺乏的依然还是build system,test harness, linter,C++社区整体比较离散,也没有大公司拿出类似js的all in one的工具链,目前用得多的是vcpkg+cmake. 也有conan和xmake等等,但相对来说还是有欠缺,主要原因是C++没有所谓的官方,只有c++标准委员会,也不像其他公司常用的编程语言会有公司推出工具链.

但C++语言本身还是不错的,足够底层,足够值得学习.

Go

Go背靠谷歌,生态目前感觉还是不够明朗,个人感觉可能是云原生基础设施上,如果你写过Go,就知道大型Web项目写Go还是有所欠缺,拿来写事务还是麻烦.

并且go的nil错误处理,module等依然遭受诟病.但是Go本身代码还是很容易读的,而且工具链也相对完善,有包管理工具,项目构建也可以使用cmake.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
"fmt"
"html/template"
"net/http"
)

type Person struct {
Name string
Age int
}

func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
p := Person{
Name: "John Doe",
Age: 30,
}
t, err := template.ParseFiles("templates/index.html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
t.Execute(w, p)
})

fmt.Println("Starting server on :8080")
http.ListenAndServe(":8080", nil)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
"fmt"
"time"
)

func worker(wrkID int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("worker %d started job %d\n", wrkID, job)
time.Sleep(time.Second)
fmt.Printf("worker %d finished job %d\n", wrkID, job)
results <- job * 2
}
}

func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)

// Start workers
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}

// Send jobs
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)

// Collect results
for a := 1; a <= 9; a++ {
fmt.Printf("Result: %d\n", <-results)
}
}

Rust

Rust,最近几年热度很高,但是也存在不少问题,上手门槛高,需要额外理解的概念不少.

Rust的一些优势包括以下几点:

  • 并发和并行:Rust内置对并行编程的支持,以及安全高效的多线程特性
  • 性能:由于Rust代码不需要运行时,同时它不需要额外的垃圾回收器功耗,从而可以使用更少的资源并提高性能,
  • 内存安全且无垃圾回收:由于所有权和借用等规则,Rust在没有垃圾回收器的情况下管理内存,从而实现更高效和可预测的性能
  • 跨平台兼容性:Rust支持跨平台开发,意味着可以在多个系统上编译代码而不需要太多的修改代码
  • 强大的生态系统:Rust拥有强大的工具和库生态系统。它的包管理器Cargo显著简化了依赖管理和与外部库集成的难度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct Person {
name: String,
age: u32,
}

impl Person {
fn new(name: &str, age: u32) -> Person {
Person {
name: String::from(name),
age,
}
}

fn greet(&self) {
println!("Hello, my name is {} and I'm {} years old.", self.name, self.name);
}
}

fn main() {
let alice = Person::new("Alice", 30);
alice.greet();
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
enum Direction {
Up,
Down,
Left,
Right,
}

fn move_player(direction: Direction) {
match direction {
Direction::Up => println!("Moving up"),
Direction::Down => println!("Moving down"),
Direction::Left => println!("Moving left"),
Direction::Right => println!("Moving right"),
}
}

fn main() {
move_player(Direction::Up);
move_player(Direction::Left);

Zig

Zig官方是这么说的:Zig 是一种通用的编程语言和工具链,用于维护健壮最优可重用的软件.

既然有了C++和Rust,为什么又要搞这么多东西?有了 C++、D 和 Rust,为什么还需要 Zig? ⚡ Zig Programming Language (ziglang.org)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const std = @import("std");
const parseInt = std.fmt.parseInt;

test "parse integers" {
const input = "123 67 89,99";
const ally = std.testing.allocator;

var list = std.ArrayList(u32).init(ally);
// Ensure the list is freed at scope exit.
// Try commenting out this line!
defer list.deinit();

var it = std.mem.tokenizeAny(u8, input, " ,");
while (it.next()) |num| {
const n = try parseInt(u32, num, 10);
try list.append(n);
}

const expected = [_]u32{ 123, 67, 89, 99 };

for (expected, list.items) |exp, actual| {
try std.testing.expectEqual(exp, actual);
}
}
1
2
3
4
5
6
7
8
const std = @import("std");

pub fn main() !void {
const x: i32 = 5;
const y: i32 = 10;
const sum = x + y;
std.log.info("The sum of {} and {} is {}", .{ x, y, sum });
}
1
2
3
4
5
6
7
8
9
10
const std = @import("std");

fn greet(name: []const u8) void {
std.log.info("Hello, {}!", .{name});
}

pub fn main() !void {
greet("Alice");
greet("Bob");
}

官方文档阐述了非常多Zig的优势,看起来特别吸引人,但是目前使用的人还是不多.

Zig的一些劣势包括:

  • 有限的生态系统:因为它仍处于早期阶段,Zig语言的生态系统比成熟语言更小
  • 成熟度和工具:Zig是一种新语言,还有改进的空间。但请注意,仍然有一个强大而活跃的社区支持它
  • 文档可用性:Zig是一种相对较新的语言,因此文档有限,社区正在努力提高文档的可用性

开发者可以在系统编程中使用Zig来构建操作系统、设备驱动程序和嵌入式系统。其还在命令行工具中也有很多应用场景,可用于创建高效和快速的命令行界面,构建系统脚本,或优化现有工具的性能。

在编译器和语言开发中,Zig以其元编程能力和对简易性的追求而闻名。比较著名的开源项目是Bun,其是一个使用Zig开发的JavaScript运行时。

与Rust一样,Zig也有一些更为专业的使用场景:

  • 游戏开发,因支持高性能游戏引擎、能够实时模拟
  • 在嵌入式系统和物联网中,用于编程微控制器、传感器和其他资源受限设备
  • 在密码应用中,用于实现加密算法、数字签名、安全通信协议和其他安全敏感组

小小的BenchmarkA “Better C” Benchmark (zserge.com)

我为什么会看上面这些语言的比较,主要原因还是:C++很好,但没有完善的工具链,它的标准委员会也不会管这些,而一些大厂也没有开源一些工具使用;

Go的生态位跟C/C++和Rust这类语言还不一样后者的一些东西不会拿Go来重构;Rust的上手门槛高,但目前看来是最可行的C/C++在系统编程、工具链重构甚至于一些业务处理上的可行工具.

而Zig还远远没有完善,但上手门槛相对更低,但应该还是需要沉淀,更何况c语言即使到今天也在更新,生态还是在的.

题外话

之前一段时间有个叫Mojo的编程语言不断在宣传自己的在AI领域编程的地位:比C和Python性能更好.Mojo 🔥: Programming language for all of AI (modular.com)

目前还在吹水建设阶段,看后续表现(其实大众看的是有没有相关大厂进局).

我常常会关注一些本身比较老但使用并不少的编程语言,因为这类编程语言有自己的生态位,文档可能不算新,官方网站也往往看起来很老,生态上也没有很大的持续发力点,但是我还是会时不时看看,毕竟其中很多可能也会用上.

PHP

之前的文章我也提到过,php生态位就是web,也是为web而生.你甚至不需要特意使用某些web框架来创建应用,它本身就支持很多操作.但是php本身有些语法还需要适应(很多人说语法丑陋).而它的web框架也特别多,从相对轻量ThinkPHP、Symfony到重型的Laravel,都可以试试.Swoole框架也使得从Web到 TCP、UDP、Socket上

还有相比swoole更易学习的workerman,workerman 是纯php写的网络框架.支持TCP长连接,支持Websocket、HTTP等协议.以及基于workerman的webman,webman用于替代传统的php-fpm架构,提供超高性能可扩展的HTTP服务。你可以用webman开发网站,也可以开发HTTP接口或者微服务

1
2
3
4
5
6
7
8
9
10
11
<?php
$numbers = array(1, 2, 3, 4, 5);
echo "The first number is: " . $numbers[0];
echo "The length of the array is: " . count($numbers);

$person = array(
"name" => "Alice",
"age" => 30
);
echo "Name: " . $person["name"] . ", Age: " . $person["age"];
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person {
private $name;
private $age;

public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}

public function greet() {
echo "Hello, my name is " . $this->name . " and I'm " . $this->age . " years old.";
}
}

$alice = new Person("Alice", 30);
$alice->greet(); // 输出 "Hello, my name is Alice and I'm 30 years old."
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function divide($a, $b) {
if ($b == 0) {
throw new \Exception("Division by zero");
}
return $a / $b;
}

try {
$result = divide(10, 0);
} catch (\Exception $e) {
echo "Error: " . $e->getMessage();
}
$greet = function($name) {
echo "Hello, $name!";
};

$greet("Alice"); // 输出 "Hello, Alice!"

$numbers = [1, 2, 3, 4, 5];
$doubledNumbers = array_map(function($x) {
return $x * 2;
}, $numbers);

print_r($doubledNumbers); // 输出 [2, 4, 6, 8, 10]

推荐学习:

Ruby

也是web生态,或者说应为rails而知名.国内相对来说没那么多使用ruby的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
numbers = [1, 2, 3, 4, 5]
puts "The first number is: #{numbers[0]}"
puts "The length of the array is: #{numbers.length}"

person = {
"name" => "Alice",
"age" => 30
}
puts "Name: #{person["name"]}, Age: #{person["age"]}"
class Person
attr_accessor :name, :age

def initialize(name, age)
@name = name
@age = age
end

def greet
puts "Hello, my name is #{@name} and I'm #{@age} years old."
end
end

# 创建 Person 对象并调用方法
alice = Person.new("Alice", 30)
alice.greet # 输出 "Hello, my name is Alice and I'm 30 years old."

推荐学习:

Lua

lua生态位是写一些游戏脚本或者一些工具的功能,比如neovim中的一些插件就会使用lua.另外一些嵌入式设备也会使用,主要是与其他语言搭配.这门语言本身非常小,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
local x = 5
local y = 10
local sum = x + y
print("The sum of " .. x .. " and " .. y .. " is " .. sum)
local fruits = {"apple", "banana", "orange"}

-- 使用for循环遍历
for i=1, #fruits do
print(fruits[i])
end

-- 使用for-in循环遍历
for _, fruit in ipairs(fruits) do
print(fruit)
end
-- 定义一个Person类
local Person = {}
function Person:new(name, age)
local obj = {
name = name,
age = age
}
setmetatable(obj, self)
self.__index = self
return obj
end

function Person:greet()
print("Hello, my name is " .. self.name .. " and I'm " .. self.age .. " years old.")
end

-- 创建Person对象并调用方法
local alice = Person:new("Alice", 30)
alice:greet()
-- 定义一个协程函数
local function count(n)
for i=1,n do
coroutine.yield(i)
end
end

-- 创建并控制协程
local co = coroutine.create(count)
print(coroutine.resume(co, 5)) -- 输出 1
print(coroutine.resume(co)) -- 输出 2
print(coroutine.resume(co)) -- 输出 3
print(coroutine.resume(co)) -- 输出 4
print(coroutine.resume(co)) -- 输出 5
print(coroutine.resume(co)) -- 输出 nil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 定义一个Vector2D类
local Vector2D = {}
Vector2D.__index = Vector2D

function Vector2D:new(x, y)
local obj = setmetatable({x=x, y=y}, Vector2D)
return obj
end

function Vector2D:add(other)
return Vector2D:new(self.x + other.x, self.y + other.y)
end

function Vector2D:__tostring()
return "(" .. self.x .. ", " .. self.y .. ")"
end

-- 创建和操作Vector2D对象
local v1 = Vector2D:new(1, 2)
local v2 = Vector2D:new(3, 4)
local v3 = v1:add(v2)
print(v3) -- 输出 (4, 6)

一些有趣的东西

[Worst Programming Languages to Learn in 2018 (codementor.io)这篇文章在2018年给出了在工作上不推荐碰的语言,其中包括Dart,Rust,Ruby,Go等,事实上从工作的角度来看,一些函数式编程语言和门槛较高的语言上榜很正常,但是另外有些更可能是因为生态还不够大,但本身是做应用的,比如Dart和Go,所以还需要官网.

这份榜单比较激进,但总体还是很有趣的.像函数时语言Clojure和Elixir就相比更老的Haskell和Erlang就更好.

在2019年Study of Programming Languages Not to Learn in 2019 (codementor.io)

这份榜单变得更符合我的知觉了,当然这些东西只是看看而已,比如下面的人就说自己拿CoffeeScript写应用到AppStore上赚了很多钱,所以,还是要看生态位.

image-20240623122150477

-------------本文结束感谢您的阅读-------------
感谢阅读.

欢迎关注我的其它发布渠道