Go语言的学习路线图
图片来自Github

我将会从翻写一个简单的java项目开始
https://github.com/jane-cloud/Open-API-SDK-V5/tree/main/okex-java-sdk-api-v5
这是Okex交易所的SDK,我之前使用过java版的,刚好没有golang版,我可以翻写一下。
这篇文章先聊一下两个语言的特性差异
特性差异
1、Go语言函数多返回值的特点
目前主流语言除Python外基本都不支持函数的多返回值功能。需求还是有的,
比如:得到一个由蜡烛图组成的行情走势 List<Candle>, size等于300条,需要求50日均线(MA50)、100日均线(MA100)、150日均线(MA150)、300日均线(MA300)。
程序的主体是一个300次的for循环,一轮循环结束,产生有4个BigDecimal值,java只能通过Map的方式返回。也不是不能解决,就是不太优雅。
public static Map<Integer, BigDecimal> MA(JSONArray array, int scale){
BigDecimal total = new BigDecimal(0);
BigDecimal total150 = new BigDecimal(0);
BigDecimal total100 = new BigDecimal(0);
BigDecimal total50 = new BigDecimal(0);
for(int i=array.size()-1; i>=0; i--) {
JSONArray candle = array.getJSONArray(i);
BigDecimal close = candle.getBigDecimal(CandleEnum.close.v());
total = total.add(close);
if(i<150){
total150 = total150.add(close);
}
if(i<100){
total100 = total100.add(close);
}
if(i<50){
total50 = total50.add(close);
}
}
Map<Integer, BigDecimal> map = new HashMap<>();
map.put(300, total.divide(new BigDecimal(300), scale, BigDecimal.ROUND_HALF_UP));
map.put(150, total150.divide(new BigDecimal(150), scale, BigDecimal.ROUND_HALF_UP));
map.put(100, total150.divide(new BigDecimal(100), scale, BigDecimal.ROUND_HALF_UP));
map.put(50, total150.divide(new BigDecimal(50), scale, BigDecimal.ROUND_HALF_UP));
return map;
}
2、也说一个Go语言不如java方便的地方,众所周知java的spring全家桶的强大,我们几乎已经是无spring不java。所以看完这个你可以不用去搜索:go有没有类似spring的框架啊?go有没有annotation的注解机制啊?不用问,问就是没有。有也不成熟,达不到你心中spring在java的高度。这时候你只能反问自己,没有spring我就不会写java了吗?如果答案不太肯定,那go就先别转了。
3、错误处理
Go语言引入了defer关键字,并提供内置函数panic、recover完成异常的抛出和捕获。让开发者无需仅仅为了程序安全性而添加大量一层套一层的try-catch语句。
4、匿名函数和闭包
f := func(x, y int) int {
return x + y
}5、Go语言不支持继承和重载
Java和C++在接口重载的特性上给我留下了阴影,在很多情况下代码会被反复修改,当修改了implements对象时interface就要一起修改,每次我都在想到底这样设计是好处多,还是增加了维护的麻烦。
public interface GuardianApi {
@GET("/api/band")
Call<JSONObject> getBand();
@GET("/api/instPoint")
Call<JSONObject> getInstPoint(@Query("instId") String instId);
@GET("/api/worker")
Call<JSONObject> getWorker();
}
到底要不要让每个service都去implements一个interface,一直都是我对java最大的怀疑
public class GuardianServiceImpl implements GuardianService {
....
@Override
public Set<String> band() {
//...
}
@Override
public InstPoint getInstPoint(String instId) {
//...
}
@Override
public Account getWorker() {
//...
}
}
Go语言的接口体系避免了这类问题
type Bird struct {
}
fuc (b *Bird) Fly(){
//...
}
type IFly interface {
Fly()
}
func main(){
var fly IFly = new{Bird}
fly.Fly()
}6、Go的并发特性
Go语言实现了CSP(通信顺序进程,Communication Sequential Process)模型来作为goroutine间的默认通信方式。在CSP模型中,一个并发系统由若干并行运行的顺序进程组成,每个进程不能对其它进程的变量赋值。进程间只能通过一对通信原语实现协作。Go语言用channel这个概念来轻松的实现了CSP模型。channel的使用方式比较接近Unix系统中的管道(pipe)概念,可以方便地进行通信。而在Java中则需要通过Netty框架来实现类似功能。
package test
import (
"fmt"
"testing"
)
func sum(values[] int, resultChan chan int) {
sum := 0
for _, value := range values {
sum += value
}
resultChan <- sum
}
func Test(t *testing.T) {
values := [] int{1,2,3,4,5,6,7,8,9,10}
resultChan := make(chan int, 2)
go sum(values[:len(values)/2], resultChan)
go sum(values[len(values)/2:], resultChan)
sum1, sum2 := <-resultChan, <-resultChan
fmt.Println("Result:", sum1, sum2, sum1 + sum2)
}
7、反射
package reflection
import (
"fmt"
"reflect"
"testing"
)
type Bird struct {
Name string
LifeExpectance int
}
func (b *Bird) Fly() {
fmt.Println("I am flying...")
}
func Test(t *testing.T) {
sparrow := &Bird{"Sparrow", 3}
s := reflect.ValueOf(sparrow).Elem()
typeOfT := s.Type()
for i :=0; i <s.NumField(); i++ {
f := s.Field(i)
fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
}
}
- Cgo
在Go语言中,可以按照Cgo的特定语法混合编写C语言代码
若有收获,就点个赞吧