Golang部份特性的C++对比实现

今天看到一篇文章<<C++ 逐渐 Python 化>>, 我个人是认为这个说法是不成立的,但这里面的一些特性对比引起了我的兴趣。

我想尝试下,Go语言所带的一些东西,在C++11中是如何做的,应当很有意思。所以刷刷刷,就有了下面的东西。

目录:

 字符串字面值

变量初始化

lambda

值顺序递增

多值赋值及函数返回多值

map查找

可变参数

回调函数

泛型

数组和切片

字面值

这个东西在两种语言中都有比较好的解决方式.Go语言用" ` "符号,C++使用R(" )"这种方式。可以省掉不少转义符的输入。

Golang

path := `c:\a\b\c\GG再也不用烦转义符了`
mulln := `"(C++/Golang
	 aa'aaa\Cplusplus/gogogo
	 author"xiongchuanliang
	`
fmt.Println(path)
fmt.Println(mulln)

C++

string path = R"(c:\a\b\c\GG再也不用烦转义符了)";
	cout << "单行:" << path.c_str() << endl;

	string muln = R"(C++/Golang
	 aa'aaa\Cplusplus/gogogo
	 author"xiongchuanliang
	)";
	cout << "多行:" << muln.c_str() << endl;

变量初始化

现在开发语言的初始化都差不多,都能很方便的定义时初始化,循环也是如下面中的C++ for循环和Go语言中的"for : rang"

形式基本一样。 另外C++的auto,Go语言中的":=",都能省代码的好东西。不过要多提一句,Go语言支持多重赋值,并且变量都

是默认就已初始化好。同时,Go语言也支持指针,但它的指针要安全得多。

Golang

var k int
fmt.Println(k)

mArr := []int{ 1, 2, 3}
var mMap = map[string]int {"a":1,"b":2}
fmt.Printf("array:%v\nmap:%v \n",mArr,mMap)

i := 10
pi := &i  //*i
ppi := &pi  //**int
fmt.Println(i,*pi,**ppi)

//结果:
0
array:[1 2 3]
map:map[a:1 b:2]
10 10 10

C++

int mArr[] = { 1, 2, 3 };
	auto mList = vector < int > {1, 2, 3, 4};
	auto mMap = map < int, string > {{1, "aa"}, { 2, "bb" }};

	cout << "vector: ";
	for (const int& x : mList)
		cout << x << " ";
	cout << endl;

	cout << "map: ";
	for (const auto& mp : mMap)
		cout << mp.first << " " << (mp.second).c_str();
	cout << endl;

lambda

lambda这东西在C++11中可是重点推荐的特性,非常的强大。Go语言自然也有,但对于闭包函数中函数外部变量的处理

并没有C++那么多种。 像C++分了四类:

[a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。

[this] 以值的方式捕获 this 指针。

[&] 以引用的方式捕获所有的外部自动变量。

[=] 以值的方式捕获所有的外部自动变量。

[] 不捕获外部的任何变量。

而Go语言默认就相当于"[=]",即,捕获可见范围内所有的外部变量。

Golang

mArr := []int{ 1, 2, 3}
	fun := func(i,v int){
		fmt.Printf("idx:%d value:%d \n",i,v)
	}
	for idx,val := range mArr{
		fun(idx,val)
	}

 C++

int arr[] = { 1, 2, 3 };
	for_each(begin(arr), end(arr), [](int n){cout << n << endl; });

	cout << "---lambda_demo---" << endl;

	auto func = [](int n){cout << n << endl; };
	for_each(begin(arr), end(arr), func);

值顺序递增(iota)

iota这个小东西很有特点,两种语言都支持且都是让数据顺序递增,从功能上看C++的iota似乎更强大灵活些。 但有意思的是,

似乎在Go语言中,iota的使用频率要高得多,被大量的用于像const定义之类的地方,有意思。

Golang

const (
		Red = iota
		Green
		Blue
	)
	fmt.Println("Red:",Red," Gree:",Green," Blue:",Blue);

C++

int d[5] = { 0 };
std::iota(d, d + 5, 10);

cout << "iota_demo(): old : d[5] = { 0 } "<< endl;
cout << "iota_demo(): iota: d[5] = { ";
for each (int var in d)
{
	cout <<  var <<" ";
}
cout <<"} "<< endl;

char e[5] = { 'a' };
char f[5] = { 0 };
copy_n(e, 5, f);

cout << "iota_demo(): old : e[5] = { 'a' } " << endl;
cout << "iota_demo(): iota: e[5]  " << endl;
std::iota(e, e + 5, 'e');
for (size_t i = 0; i < 5; i++)
{
	cout << "                      old = " << f[i] << " iota = " << e[i] << endl;
}

//结果:
值顺序递增
iota_demo(): old : d[5] = { 0 }
iota_demo(): iota: d[5] = { 10 11 12 13 14 }
iota_demo(): old : e[5] = { 'a' }
iota_demo(): iota: e[5]
 iota = e
 iota = f
 iota = g
 iota = h
 iota = i
值顺序递增 end.

多值赋值及函数返回多值

这个功能在Go语言中相当方便,C++中则需要使用tuple和 tie等才能实现,有点麻烦,但效果是一样的。

Golang

func tuple_demo()(int,string){

	a,b := 1,2
	fmt.Println("a:",a," b:",b);

	c,d := b,a
	fmt.Println("c:",c," d:",d);

	return 168, "函数返回的字符串"
}

 C++

tuple<int, string> tuple_demo(){
	tuple<int, string> ret;
	ret = make_tuple(168, "函数返回的字符串");
	cout << "tuple_demo(): " << get<0>(ret) << " " << (get<1>(ret)).c_str() << endl;

	auto triple = make_tuple(5, 6, 7);
	cout << "tuple_demo(): " << get<0>(triple) << " " << get<1>(triple) << " " << get<2>(triple) << endl;

	int ti;
	string ts;
	tie(ti, ts) = make_tuple(10, "xcl--将数字和字符赋值给两个变量");
	cout << "tuple_demo(): " << ti << " " << ts.c_str() << endl;

	return ret;
}

//调用:
int ti;
string ts;
tie(ti, ts) = tuple_demo();
cout << "main() <- tuple_demo(): " << ti << " " << ts.c_str() << endl;

//结果:
多值赋值及函数返回多值
tuple_demo(): 168 函数返回的字符串
tuple_demo(): 5 6 7
tuple_demo(): 10 xcl--将数字和字符赋值给两个变量
main() <- tuple_demo(): 168 函数返回的字符串
多值赋值及函数返回多值 end.

map查找

Go语言中map的查找特别方便. 要找个值,直接map[key]就出来了。C++也可以直接用find(key)的方式,但Go语言直接有个

found的匿名变量,能告知是否有找到,这个要比C++去比end(),要直观些,也可以少打些字。

Golang

var mMap = map[string]int {"a":1,"b":2,"c":3}
	val,found := mMap["b"]
	if found {
		fmt.Println("found :",val);
	}else{
		fmt.Println("not found");
	}

C++

typedef map <string, int > map_str_int;
tuple<string, int, bool> mapfind_demo(map_str_int myMap, string key){

	map_str_int::iterator pos;
	pos = myMap.find(key);
	if (pos == myMap.end()){
		return make_tuple("", 0, false);
	}
	else{
		return make_tuple(pos->first, pos->second, true);
	}
}

//调用:
auto myMap = map_str_int{ { "aa", 1 }, { "bb", 2 }, { "cc", 3 } };

string mpKey;
int mpValue;
bool  mpFound = false;
tie(mpKey, mpValue, mpFound) = mapfind_demo(myMap, "bb");

if (mpFound){
	cout << "mapfind_demo: found" << endl;
}
else{
	cout << "mapfind_demo: not found" << endl;
}

可变参数

可变参数是指函数的最后一个参数可以接受任意个参数,我在用Go语言实现的args_demo()例子中,用了效果一样的两种不同

调用方法来展示Go语言对这个下的功夫。然后可以再看看通过C++模板实现的,一个比较有代表性的Print函数来感受感受C++

对这个可变参数的处理方式。

Golang  

func args_demo(first int,args ...int){
	fmt.Println("ars_demo first:",first)
	for _,i := range args {
		fmt.Println("args:",i)
	}
}

//调用
args_demo(5,6,7,8);
mArr := []int{ 5, 6, 7,8}
args_demo(mArr[0],mArr[1:]...);

fmt.Println("fmtPrintln(): ", 1, 2.0, "C++11", "Golang");

执行结果
变量fmtPrintln():  1 2 C++11 Golang
ars_demo first: 5
args: 6
args: 7
args: 8
ars_demo first: 5
args: 6
args: 7
args: 8

C++

template<typename T> void fmtPrintln(T value){
	cout << value << endl;
}

template<typename T, typename... Args>
void fmtPrintln(T head, Args... args)
{
	cout << head << " ";
	fmtPrintln(args...);
}

//调用
fmtPrintln("fmtPrintln(): ", 1, 2.0, "C++11", "Golang");

//执行结果:
变长参数
fmtPrintln():  1 2 C++11 Golang
变长参数 end.

回调函数

对比看看两种语言函数的回调处理。实现方法没啥差异。

Golang

type funcType func(string)

func printFunc(str string){
	fmt.Println( "callFunc() -> printFunc():",str)
}

func callFunc(arg string,f funcType){
	f(arg)
}

callFunc("回调就是你调我,我调它,大家一起玩。",printFunc)

C++

void printFunc(string arg){
	cout << "callFunc() -> printFunc():" << arg.c_str() << endl;
}

typedef void(*callf)(string);
void callFunc(callf pFunc, string arg){ //void(*pFunc)(string)
	pFunc(arg);
}
callFunc(printFunc, "回调就是你调我,我调它,大家一起玩。");

泛型

C++泛型就不用多说了,都知道有多强大。Go语言要加入这个不知道是啥时候的事,不过通过简单的反射,还

是可以实现类似的功能,但代码有点长。

Golang

func compare(v1, v2 interface{}) (int, error) {

	switch v1.(type) {
	case int:
		if v1.(int) < v2.(int) {
			return -1, nil
		} else if v1.(int) == v2.(int) {
			return 0, nil
		}
	case int8:
		if v1.(int8) < v2.(int8) {
			return -1, nil
		} else if v1.(int8) == v2.(int8) {
			return 0, nil
		}
	case int32:
		if v1.(int32) < v2.(int32) {
			return -1, nil
		} else if v1.(int32) == v2.(int32) {
			return 0, nil
		}

	//省略......

	default:
		return -2, errors.New("未能处理的数据类型.")
	}
	return 1, nil
}

//调用:
v1 := 13
v2 := 53
ret, err := compare(v1, v2)
if err != nil {
	fmt.Println(err)
	return
}
switch ret {
case -1:
	fmt.Println("v1 < v2")
case 0:
	fmt.Println("v1 == v2")
case 1:
	fmt.Println("v1 > v2")
default:
	fmt.Println("defualt")
}

C++

template <typename T> int compare(const T v1, const T v2){
	if (v1 < v2){
		cout << "compare(): v1 < v2" << endl;
		return -1;
	}
	else if (v1 == v2){
		cout << "compare(): v1 == v2" << endl;
		return 0;
	}
	else{
		cout << "compare(): v1 > v2" << endl;
		return 1;
	}
}

//调用:
int i1 = 5, i2 = 7;
double d1 = 52.5, d2 = 10.7;
compare(i1, i2);
compare(d1, d2);

数组和切片(sclie)

数组/切片Go语言做得非常灵活,不一一举例,这里主要可以看看C++的。我用copy_n,copy_if 模拟二下简单的切片功能。

Golang

    a := [5]int{ 1, 2, 3, 4, 5 }
    b := a[:3]
    c := a[1:2]
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
    
//运行结果:<span style="white-space:pre">	</span>
[1 2 3 4 5]
[1 2 3]
[2]

C++

	int a[5] = { 1, 2, 3, 4, 5 };
	int b[3] = { 0 };
	int c[2] = { 0 };

	cout << "a[5] = { 1, 2, 3, 4, 5 }" << endl;
	cout << "array[:end_pos]: b = array[:3]" << endl;
	// array[:end_pos]
	copy_n(a, 3, b);
	for each (int var in b)
	{
		cout << " " << var;
	}
	cout << endl;

	cout << "a[5] = { 1, 2, 3, 4, 5 }" << endl;
	cout << "array[begin_pos:end_pos]: c = array[1,2] " << endl;
	// array[begin_pos:end_pos]
	int begin_pos = 1;
	int subLen = sizeof(c) / sizeof(c[0]);
	int end_pos = begin_pos + subLen;
	copy_if(a + begin_pos, a + end_pos, c, [](int v){return true; });

	for each (int var in c)
	{
		cout << " " << var ;
	}
	cout << endl;

//运行结果:
数组和切片(sclie)
a[5] = { 1, 2, 3, 4, 5 }
array[:end_pos]: b = array[:3]
 1 2 3
a[5] = { 1, 2, 3, 4, 5 }
array[begin_pos:end_pos]: c = array[1,2]
 2 3
数组和切片(sclie) end.

很粗浅的分别实现下这几个点,体会是C++很强大,Golang更纯粹,少即是多。

Go语言和C++完整测试源码我放在: https://github.com/xcltapestry/xcltools/tree/master/cplusplus_golang 上。

可以自行下载编译。

MAIL: [email protected]

Blog:http:/blog.csdn.net/xcl168

时间: 2024-10-08 22:24:29

Golang部份特性的C++对比实现的相关文章

flipt 一个基于golang 的特性工具开发类库

以前介绍过一个Flagr 的基于golang 的特性功能开发类库(技术雷达推荐),今天看到一个类似也很不错的方案flipt 参考架构 包含的特性 快速,使用golang 编写,同时进行了性能优化 运行以及配置简单 可以对于特定分段的用户配置分发规则 native grpc 支持 可以方便进行应用集成 提供了方便的rest api 提供了console 以及UI 可以方便进行debug 参考资料 https://flipt.dev/architecture/ https://github.com/

Golang string和[]byte的对比

为啥string和[]byte类型转换需要一定的代价?为啥内置函数copy会有一种特殊情况copy(dst []byte, src string) int?string和[]byte,底层都是数组,但为什么[]byte比string灵活,拼接性能也更高(动态字符串拼接性能对比)? 何为string?什么是字符串?标准库builtin的解释: 简单的来说字符串是一系列8位字节的集合,通常但不一定代表UTF-8编码的文本.字符串可以为空,但不能为nil.而且字符串的值是不能改变的.不同的语言字符串有

[golang] 基于 golang interface 特性衍生的任务流处理思维

在设计程序的许多应用场景中我们会遇到大体分为三个阶段的任务流. 第一.入口 一个或多个入口,等待阻塞的.或者主动请求方式的. ============================== 比如任务流需要接受来自于 HTTP 和 FTP 的应用请求,后续还有可能增加别的方式的接受请求. 第二.处理 多个入口可以对应一个处理程序,也可以对应多个处理程序. ================================== 比如 HTTP 和 FTP 的多个入口程序需要对应一个和多个处理逻辑,同样也

PullToRefresh开源控件和5.0新特性SwipeRefreshLayout的对比使用

PullToRefresh开源控件可以实现下拉和上拉刷新数据,而后者SwipeRefreshLayout主要用于下拉刷新,知乎的首页刷新数据用的就是这个控件. 一,先介绍PullToRefresh开源控件的使用 PullToRefresh开源控件可以实现下拉和上拉刷新数据,在项目中首先要导入这个包,可以先从github上进行下载,之后在Android Studio中进行导入,之前试了直接导入总会报错,后来直接右键New Module,新建android library即可,按照PullToRef

golang语言特性

1. 垃圾回收 a. 内存?动回收,再也不需要开发?员管理内存 b. 开发人员专注业务实现,降低了心智负担 c. 只需要new分配内存,不需要释放 2. 天然并发 a. 从语?层面?持并发,?常简单.只需要go一下 b. goroutine,轻量级线程,创建成千上万个goroute成为可能 3. channel a. 管道,类似unix/linux中的pipe b. 多个goroute之间通过channel进行通信 c. ?支持任何类型 4. 多返回值 a. ?个函数返回多个值 5. 编译型语言

RocketMQ与Kafka对比(18项差异)

转自:https://github.com/alibaba/RocketMQ/wiki/rmq_vs_kafka 淘宝内部的交易系统使用了淘宝自主研发的Notify消息中间件,使用Mysql作为消息存储媒介,可完全水平扩容,为了进一步降低成本,我们认为存储部分可以进一步优化,2011年初,Linkin开源了Kafka这个优秀的消息中间件,淘宝中间件团队在对Kafka做过充分Review之后,Kafka无限消息堆积,高效的持久化速度吸引了我们,但是同时发现这个消息系统主要定位于日志传输,对于使用在

转发:RocketMQ与kafka的对比

淘宝内部的交易系统使用了淘宝自主研发的Notify消息中间件,使用Mysql作为消息存储媒介,可完全水平扩容,为了进一步降低成本,我们认为存储部分可以进一步优化,2011年初,Linkin开源了Kafka这个优秀的消息中间件,淘宝中间件团队在对Kafka做过充分Review之后,Kafka无限消息堆积,高效的持久化速度吸引了我们,但是同时发现这个消息系统主要定位于日志传输,对于使用在淘宝交易.订单.充值等场景下还有诸多特性不满足,为此我们重新用Java语言编写了RocketMQ,定位于非日志的可

从RAID0,RAID1和RAID5特性谈raid类数据恢复

RAID类磁盘阵列各有什么特色?RAID0, RAID1和RAID5等磁盘阵列的安全性如何?本文通过RAID0,RAID1和RAID5特性以及安全性对比,谈谈这几种常见RAID阵列的数据安全性以及恢复难度. 首先,我们需要认识磁盘阵列RAID,RAID将普通硬盘组成一个磁盘阵列,在主机写入数据,由于采用并行读写操作,从而提高了存储系统的存取系统的存取速度.它共有九个模式,以数字命名,为RAID 0.RAID1到RAID 7以及RAID 0+1,而目前最常见的是RAID 0.RAID 1.RAID

go语言的特性

一.golang语言特性 1. 垃圾回收 a.内存自动回收,再也不需要开发人员管理内存  //开发代码中不能存在无引用的变量,不然代码出错 b.开发人员专注业务实现,降低了心智负担 c.只需要new分配内存,不需要释放 2. 天然并发 a.从语言层面支持并发,非常简单 b.goroute,轻量级线程,创建成千上万个goroute成为可能 c.基于CSP(Communicating Sequential Process)模型实现(基于goroute.channel) 并发实例: 不需要担心编码问题