您的位置:

golang泛型,golang泛型 json解析

本文目录一览:

尝试用golang 1.18泛型实现orm

这几天golang社区对泛型的讨论非常多的,一片热火朝天的景象。对我们广大gopher来说总归是好事。

泛型很有可能会颠覆我们之前的很多设计,带着这种疑问和冲动,我准备尝试用golang泛型实现几个orm的常见功能。

本文并没完全实现通用的orm,只是探讨其实现的一种方式提供各位读者做借鉴。

虽然golang有了泛型,但是目前在标准库sql底层还没有改造,目前还有很多地方需要用到reflect。

调用方式

这个部分跟传统的orm使用上没有太大区别,没办法不使用反射的情况下,泛型的方式可能变得有点繁琐。

调用方式

和创建table类似,写入数据好像比没有之前的orm有优势。

读取数据是非常高频的操作,所以我们稍作封装。

调用方式

稍微比原先的orm方式有了多一点想象空间,比如 在[T any]做更明确的约束,比如要求实现Filter定制方法。

鉴于本人能力还认证有限,目前还没有发现泛型对orm剧烈的改进和突破的可能。未来如果go对底层sql做出改动,或者实现诸如Rust那种Enum方式,可能会带来更多的惊喜。

大家知道为什么golang不支持泛型

Golang团队认为在类型系统和运行时的复杂性花费太大,还没找到可以和这个复杂性相抵的良好设计。内置的map和slice其实都有泛型的味道,加上可以用interface{}来构造容器,可以达到泛型的效果。所以目前为止还没有直接的支持泛型。

golang泛型前瞻

9月更新了 golang设计草稿中的泛型语法

这里可以在线编译

如下

这是一个泛型的Print函数 循环打印泛型切片中的元素

any是一种特殊的interface 在我的理解中 any可以看做包含基本类型在内的所有类型

除any外可以声明任意一个包括多种基本类型的interface 如

有了Ordered可以实现一个比较函数:

当Gte的参数在Ordered的类型列表中时编译可以通过

当Ordered的类型列表中的类型不支持=运算符时 编译失败

一个map函数的例子

对切片s中的每一个元素执行f 返回一个结果集

如何看待go语言泛型的最新设计?

Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成为现实。Go 团队实施了一个看起来比较稳定的设计草案,并且正以源到源翻译器原型的形式获得关注。本文讲述的是泛型的最新设计,以及如何自己尝试泛型。

例子

FIFO Stack

假设你要创建一个先进先出堆栈。没有泛型,你可能会这样实现:

type Stack []interface{}func (s Stack) Peek() interface{} {

 

return s[len(s)-1]

}

func (s *Stack) Pop() {

 *s = (*s)[:

len(*s)-1]

}

func (s *Stack) Push(value interface{}) {

 *s = 

append(*s, value)

}

但是,这里存在一个问题:每当你 Peek 项时,都必须使用类型断言将其从 interface{} 转换为你需要的类型。如果你的堆栈是 *MyObject 的堆栈,则意味着很多 s.Peek().(*MyObject)这样的代码。这不仅让人眼花缭乱,而且还可能引发错误。比如忘记 * 怎么办?或者如果您输入错误的类型怎么办?s.Push(MyObject{})` 可以顺利编译,而且你可能不会发现到自己的错误,直到它影响到你的整个服务为止。

通常,使用 interface{} 是相对危险的。使用更多受限制的类型总是更安全,因为可以在编译时而不是运行时发现问题。

泛型通过允许类型具有类型参数来解决此问题:

type Stack(type T) []Tfunc (s Stack(T)) Peek() T {

 

return s[len(s)-1]

}

func (s *Stack(T)) Pop() {

 *s = (*s)[:

len(*s)-1]

}

func (s *Stack(T)) Push(value T) {

 *s = 

append(*s, value)

}

这会向 Stack 添加一个类型参数,从而完全不需要 interface{}。现在,当你使用 Peek() 时,返回的值已经是原始类型,并且没有机会返回错误的值类型。这种方式更安全,更容易使用。(译注:就是看起来更丑陋,^-^)

此外,泛型代码通常更易于编译器优化,从而获得更好的性能(以二进制大小为代价)。如果我们对上面的非泛型代码和泛型代码进行基准测试,我们可以看到区别:

type MyObject struct {

    X 

int

}

var sink MyObjectfunc BenchmarkGo1(b *testing.B) {

 

for i := 0; i  b.N; i++ {

  

var s Stack

  s.Push(MyObject{})

  s.Push(MyObject{})

  s.Pop()

  sink = s.Peek().(MyObject)

 }

}

func BenchmarkGo2(b *testing.B) {

 

for i := 0; i  b.N; i++ {

  

var s Stack(MyObject)

  s.Push(MyObject{})

  s.Push(MyObject{})

  s.Pop()

  sink = s.Peek()

 }

}

结果:

BenchmarkGo1BenchmarkGo1-16     12837528         87.0 ns/op       48 B/op        2 allocs/opBenchmarkGo2BenchmarkGo2-16     28406479         41.9 ns/op       24 B/op        2 allocs/op

在这种情况下,我们分配更少的内存,同时泛型的速度是非泛型的两倍。

合约(Contracts)

上面的堆栈示例适用于任何类型。但是,在许多情况下,你需要编写仅适用于具有某些特征的类型的代码。例如,你可能希望堆栈要求类型实现 String() 函数