Java开发人员的Go语言入门01-Go语言介绍

官方文档

Golang简称为Go,官方网站https://golang.org已迷失,可以通过如下国内的网站上手入门

  • Go的中文api文档:https://studygolang.com/pkgdoc

  • Go的中文入门文档:http://docscn.studygolang.com/doc/

  • Go的中文社区网址:https://studygolang.com

学习的目的

Go语言目前还是是小而美的语言,夸张的说法:全中国大概60%的开发岗位与java有关,而Go?

作为一个程序员,掌握底层的知识:操作系统、算法、数据结构、计算机原理、网络原理

其实任何一门语言上手都是三天(Java基础),如果有C/C++语言基础,上手时间可以缩短到一天

一定一定不要放弃架构师思维,这个才是更宽、天花板更高的路

招Go语言的都是非常有名的公司,要意识到单纯学Go,只是拓宽个人的知识面

  • 讲给Java开发者的Go入门
  • 架构知识的加分项
  • 并非给小白读者

Go VS Java

指针

  • Java中没有指针

  • C指针繁琐在指针运算

  • Go语言没有指针运算

关键字&

  • Go语言这个&符号就是取地址
  • C++ 引用(别名) 同时也是取地址
package main

import "fmt"
// 指针的使用
func main() {
   var i = 8
   fmt.Println(&i)

   var p = &i
   fmt.Println(p)
}

为什么Go语言中要设计指针?引用传递 vs 值传递

关键字*

Java直接传引用
public class ReferenceUseage {

    public static void main(String[] args) {
        P p = new P();
        p.name = "zhang san";
        modifyName(p);
        System.out.println(p.name);
    }

    public static void modifyName(P p){
        p.name = "si li";
    }
}

class P {
    String name;
}

以上Java代码最后输出si li,因为Java在方法中的参数默认是传引用。

Go语言默认是传值
package main

import "fmt"

type P struct {
	name string
}

func modifyName(p P){
	p.name = "li si"
}

func main() {
	var p =  P{name: "zhang san"}
	modifyName(p)
	fmt.Println(p.name)
}

以上Go代码最后输出zhang san,因为Go的参数传递方式为传值,传递到modifyName函数中,已经复制了整个参数的值,修改的是复制对象,不会影响到原对象。

Go的引用传递
package main

import "fmt"

type P struct {
	name string
}

func modifyNameByReference(p *P){
	p.name = "li si"
}

func main() {
	var p =  P{name: "zhang san"}
	modifyNameByReference(&p)
	fmt.Println(p.name)
}

以上代码声明modifyNameByReference时使用*关键字,就表示使用引用方式传参,同时注意函数调用时使用&关键字对参数进行取地址。

使用引用传参后,最后输出结果就为li si

解引用

*除了表示指针类型,还可以用来表示解引用

package main

import "fmt"

func f(v *int){
	*v = 8
}
func main() 
	m := 0
	f(&m)
	fmt.Println(m)
}

以上代码输出结果为8,解引用可以理解为&取地址的反运算

函数

函数是Go语言中的一等公民

Go语言吸收了很多函数式编程的思想,类似JavaScript

其他函数式语言:JavaScript/python/scala

函数式语言的典型特性:Lambda表达式

指向函数的指针

理解如下代码,通过定义函数,函数指针,可以将函数指针作为参数进行传递,完成功能的调用

package main

import "fmt"

func andBodySay(f func(word string)){
   f("hello")
}

func main() {
   var ff func(word string)
   var f1 = func(word string){
      fmt.Println(word, " f1")
   }

   ff = f1
   fmt.Println(ff)

   ff("haha")
   f1("haha")

   andBodySay(f1)

   var f2 = func(word string){
      fmt.Println(word, " f2")
   }

   andBodySay(f2)
}

以上代码输出

0x10a6be0
haha  f1
haha  f1
hello  f1
hello  f2

对比Java,可在Lambda表达式中找对对应的用法

public class LambdaUsage {
    public static void main(String[] args) {
        Runnable hello = () -> System.out.println("hello");
        new Thread(hello).start();
    }
}

Java之前是没有函数式编程的概念的,后续才吸收的Lambda表达式

不准确的理解:Go语言中的函数指针可以类比 Java中的函数签名

通过函数指针的变换就好像可以实现Java中的多态

并发

Go语言抢Java C C++ php的市场的关键点

Go routine(协程) v.s Java中的线程

Go语言最大的特点,非常适合开发基于网络的中间件

Go语言网络通信

Go语言的Tcp客户端代码

package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

func main() {
  // 多个返回值(元组/tuple),只取第一个conn
	conn, _:= net.Dial("tcp", "localhost:8888")
	 
	fmt.Println(conn)

	log.Println("connected")
  
  // 类比Java中的finally,保证函数退出之前调用
	defer conn.Close()

  // 将conn中的数据读出打印到标准输出
	io.Copy(os.Stdout, conn)
}

Go语言的Tcp Server端代码

package main

import (
   "fmt"
   "io"
   "log"
   "net"
   "time"
)

func main() {
   listener, err := net.Listen("tcp", "localhost:8888")
   
   if err != nil {
      log.Fatal(err)
   }
   
   for {
      conn, err := listener.Accept()
      if err != nil {
         log.Fatal(err)
      }
      
      fmt.Println("a client connected:", conn.LocalAddr())
      // 阻塞,只能处理一个客户端
      handle(conn)
   }
}

func handle(conn net.Conn) {
   defer conn.Close()
   for  {
      _, err := io.WriteString(conn, "hello")
      if err != nil {
         log.Fatal(err)
      }

      time.Sleep(1* time.Second)
   }
}

目前这样的Server在handle(conn)会直接阻塞,而想要实现类似Java多线程的效果只需要将

handle(conn)

修改为

go handle(conn)

加上一个关键字go就实现类比Java多线程的机制,那Go语言底层是如何实现的呢?

routing:协程

Gorouting的GPM模型

GPM -> Goroutine Processor Machine

Go语言维护了多个线程,每个线程维护一个协程队列,就好像Java中的线程池(Java Thread Pool/Fork Join Pool)
在这里插入图片描述

讨论

  • 为什么协程快?
    • 不快,并不比线程池快(Netty > Go)
    • 有些情况比线程快,起1万个协程比起1万个线程快
    • 节省的是线程切换的支出
  • 完成等同于线程池的任务?
    • 线程池的task,不具备协程能力
    • Golang中可以用channel来做协程协调
      • 在用户空间模拟了CPU切换
  • 协程怎么回收?
    • 执行完回收
  • Golang中的异步(没有异步)
    • 因为到处都是异步
    • 同步的写法完成异步的操作(流行的原因,写起来简单)
  • Go语言GC性能不如Java

版权说明

本文章内容为马士兵教育《Golang 4 Javaer》课程的学习笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值