写在前面:翻了很多博客,一直没有Java选手转行golang的学习经验贴,思考很久,写下这篇Java选手怎么看待golang这个冉冉新星。

1.走完所有golang基础之后的感受

(1)最大的不适应有这么几点:

  •         ---变量定义时,变量类型放在后面,如var temp string;但是Java是在前面,比如int a;
  •         ---新建对象时,在go中常用下面这么几种,make()、new()、&引用传递

                在新建map、chan、slice时,我们常用make,可以快速创建,并且赋空值,而new和&常用来新建结构体或者接口时使用,可以快速返回创建的对象的引用。

	//对象创建var temp1 chan stringtemp1 = make(chan string, 2) //带缓冲区var temp2 []inttemp2 = make([]int, 10)var temp3 map[int]stringtemp3 = make(map[int]string)var temp4 *dto.Womantemp4 = &dto.Woman{Age1:  0,Name1: "",}temp4.Name("嘿嘿嘿")var temp5 *dto.Mentemp5 = new(dto.Men)temp5.Name("嘎嘎嘎")temp1 <- "12"temp2[0] = 1temp3[12] = "12"
  •                 ---接口方面,没有严格的implements接口,只是可以新定义struct,然后实现这个接口的所有方法,相当于间接实现了这个接口。
	var temp4 dto.Mantemp4 = &dto.Woman{Age1:  0,Name1: "",}

tips:

Go 的接口变量本身是一个 ​双字结构​(two-word structure),包含:

  1. 动态类型信息​(指向具体类型的元数据)
  2. 动态值​(指向实际数据的指针或值)

声明接口类型时,无需声明为指针类型,事实上,接口类型可以指向任何类型,本身接口就可以是一个指针类型

(2)基本类型

golang相比Java,缩减了非常多的API,Java里的List,Set,HashMap全被砍掉,数组进行了保留。

Java基础数据类型有8种,int、long、short、float、double、byte、boolean、char

Golang基础数据类型有7种,整型(6种)byte、int、int8、int16、int32、int64、无符号整型(6种):uint、uint8、uint16、uint32、uint64、uintptr,浮点型(2种)float32、float64,复数类型(2种):complex64,complex128、字符:rune、字符串:string

并且Golang还有一些符合数据类型,如指针、数组,切片(类似Python),结构体(可以和C++的结构体类比,但是我把他理解成Java的类),还有并发编程的channel等

tips:go中的数组类型,在 Go 语言中,数组的大小是类型的一部分,因此不同大小的数组是不兼容的,也就是说 [5]int 和 [10]int 是不同的类型。

int在Go语言中,会根据机器情况是64位还是32位进行变化,建议显示声明int64还是int32

(3)输入输出流

golang的打印函数和c++、python的比较类似,使用printf打印可以格式化

(4)go的函数调用

go中,函数不基于结构体而是基于包名调用,方法基于结构体调用。在go中,没有类的概念,struct就类似于类的概念,方法归属于结构体,只有结构体被实例化时,才能调用这个结构体的方法,但是函数如果首字母大写,通过包名,是能够全局调用到的。

在Java中,是没有函数这个概念的,只有方法的概念,而方法都是归属于类的,同样,方法只有类被实例化后,才能被这个实例调用到。

(5)多线程

        Java中线程可以继承Thread,实现Runnalbe接口,或者实现Callable接口,或者从线程池创建。Java 语言里解决并发问题靠的是多线程,但线程是个重量级的对象,不能频繁创建、销毁,而且线程切换的成本也很高,我们可以使用线程池维护一些线程的复用,ThreadPollExcutor,另外针对并发问题,Java有各种工具类,放在concurrent包下,例如countdownlatch,rw锁,concurrenthashmap,CopyOnWriteArrayList,ThreadLocalRandom,wait&notify,await&notifyALL,AtomicInteger在内的各种自增原子类,不得不说,Java的生态真的好,各种工具类用到你手软,而且是内置到JDK中!!!无需你自己去挑第三方包

        而且从JDK21后开始全面支持虚拟线程,使用也非常简单,API方法完全一样,只是创建的时候加上ofVirtual,下面给出实例

public class Main {public static void main(String[] args) throws InterruptedException {long start = System.currentTimeMillis();List<Thread> threads = IntStream.range(0, 1_000_000).mapToObj(i -> Thread.ofVirtual()  // 替换为ofPlatform()测试传统线程
//                .mapToObj(i -> Thread.ofPlatform()  // 替换为ofPlatform()测试传统线程.start(() -> {try {Thread.sleep(100);} catch (InterruptedException ignored) {}})).toList();for (Thread thread : threads) {thread.join();}long end = System.currentTimeMillis();System.out.println("Total time: " + (end - start) + "ms");}
}

        但是,go的简化设计,虽然没有Java丰富,但是其小而美的设计依然可以满足大部分简单的场景,如下所示。

权限描述符

Java的权限描述符有private,public,protected,default

Golang中则是,如变量,结构体,方法等首字母大写,则其他包都可以访问,首字母小写,则不可访问

2.go几个比较重要的点

(1)select语句

  • 每个 case 都必须是一个通道
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通道可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,select 会随机公平地选出一个执行,其他不会执行。
    否则:
    1. 如果有 default 子句,则执行该语句。
    2. 如果没有 default 子句,select 将阻塞,直到某个通道可以运行;Go 不会重新对 channel 或值进行求值。

(2)高级特性

  • context.WithCancel、context.WithTimeout可以通过上下文通知其他线程统一进行取消或者进行超时释放。
  • sync.Mutex 提供互斥锁,还有RWMutex读写锁
  • 使用waitGroup+chan+context.WithCancel实现多线程的通信,模拟某一线程报错时,用可取消上下文来终止所有线程的运行
func MyWork(ctx context.Context, flag int, wg *sync.WaitGroup, erCh chan error) {defer wg.Done()for {select {case _ = <-ctx.Done():fmt.Printf("当前线程优雅退出%d\n", flag)returndefault:if time.Now().UnixNano()%5 == 0 {erCh <- errors.New("error happened")fmt.Printf("当前线程自行退出%d\n", flag)return}fmt.Println("当前线程正在执行任务{}", flag)time.Sleep(1 * time.Second)}}}
func main(){var erCh chan errorerCh = make(chan error, 3)var wg = &sync.WaitGroup{}ctx, cancel := context.WithCancel(context.Background())go func() {if err := <-erCh; err != nil {fmt.Println("发生错误")cancel()}}()for i := 0; i < 3; i++ {wg.Add(1)go sync2.MyWork(ctx, i, wg, erCh)}wg.Wait()close(erCh)fmt.Println("所有协程优雅退出")
}

(3)go语言中的参数传递(值传递和指针传递)

	var once sync.Oncevar wg *sync.WaitGroupwg = &sync.WaitGroup{}onceBody := func() {fmt.Println("Only execute once")}for i := 0; i < 5; i++ {wg.Add(1)go func() {defer wg.Done()once.Do(onceBody)}()}wg.Wait()
	var once sync.Oncevar wg sync.WaitGrouponceBody := func() {fmt.Println("Only execute once")}for i := 0; i < 5; i++ {wg.Add(1)go func() {defer wg.Done()once.Do(onceBody)}()}wg.Wait()

注意看,两段代码执行都能成功,一个使用了waitGroup的引用,一个是值

但是在多线程中,都能操作统一个waitGroup,这是为什么呢?按理说,值传递的话,wg进行扣除的时候,应该是使用的拷贝副本信息,但依然执行正确

事实上,匿名函数闭包直接引用外部的 wg,Go 会自动处理为指针操作,等效于

go func(wgPtr *sync.WaitGroup) {defer wgPtr.Done()
}(&wg)

go自动将值传递变成了引用传递

这样的情况也发生在显式参数传递上,例如下面的例子

type Person struct {age int
}func (p Person) howOld() int {return p.age
}func (p *Person) growUp() {p.age += 1
}func main() {// qcrao 是值类型qcrao := Person{age: 18}// 值类型 调用接收者也是值类型的方法fmt.Println(qcrao.howOld())// 值类型 调用接收者是指针类型的方法qcrao.growUp()fmt.Println(qcrao.howOld())// ----------------------// stefno 是指针类型stefno := &Person{age: 100}// 指针类型 调用接收者是值类型的方法fmt.Println(stefno.howOld())// 指针类型 调用接收者也是指针类型的方法stefno.growUp()fmt.Println(stefno.howOld())
}

总结就是下面,对于可引用的类型,在转化时可升级成指针

-值接收者指针接收者
值类型调用者方法会使用调用者的一个副本,类似于“传值”使用值的引用来调用方法,上例中,qcrao.growUp() 实际上是 (&qcrao).growUp()
指针类型调用者指针被解引用为值,上例中,stefno.howOld() 实际上是 (*stefno).howOld()实际上也是“传值”,方法里的操作会影响到调用者,类似于指针传参,拷贝了一份指针

 (4)slice切片

golang里使用slice可变数组来模拟List的效果,底层原理依然是使用数组来实现,slice底层数据结构维护三个字段:引用的数组、slice长度、slice容量,可以通过len()和cap()查切片的长度和容量,可以参考下面示例来理解slice的工作原理

	i1 := [5]int{1, 2}slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}s1 := slice[2:5]s2 := s1[2:6:7]s2 = append(s2, 100)s2 = append(s2, 200)s1[2] = 20fmt.Println(i1)fmt.Println(s1)fmt.Println(s2)fmt.Println(slice)

-对于数组i1的打印,直接打印[1 2 0 0 0],对于未赋初值的index,默认是0

-对于slice切片,初始化为[0 1 2 3 4 5 6 7 8 9],len=10,cap=10

-s1切片,从slice的下标2开始截取,截取长度为5-2=3,s1容量未明确说明,默认使用指向的数组的长度10,所以s1的容量cap为10-2=8,此时如果print的话,应该为[2,3,4],但其底层指向的数组实际上是[2,3,4,5,6,7,8,9],但并不会被打印出来

-s2切片,从s1的下标2开始截取,截取长度为6-2=4,容量为7-2=5,此时如果print的话,应该为[4,5,6,7],实际底层指向的数组为[4,5,6,7,8],但并不会被打印出来

-对切片s2进行append100后,容量够用,变为[4,5,6,7,100],len=5,cap=5,由于s1,s2,slice都指向同一个底层数组的指针,所以会同步修改slice=[0,1,2,3,4,5,6,7,100,9] s1=[2,3,4,5,6,7,100,9]

-对切片s2再进行append200后,容量不够用,需要扩容,会将原数组复制一份,指向新的数组s2=[4,5,6,7,100,200,-,-,-,-],len=6,cap=10,此时,s2不再与s1和slice的底层数组指向同一处。

-s1[2]=20,会同步修改s1和slice,所以s1=[2,3,20,5,6,7,100,9],slice=[0,1,2,3,20,5,6,7,100,9]

运行结果如下,证明猜想正确

 (5)for+range遍历

go语言提供了更加全面的遍历方法,使用for+range来遍历数组、slice、map、chan,来获取不同的值,对于map,返回key和value;对于数组和slice,返回index和value;对于chan,返回value  。当然,其实Java借助Lamda表达式,可以更简单的实现所有对象类型的遍历。

	var map1 map[string]stringmap1 = make(map[string]string)map1["mellowChen"] = "mellowChen"map1["yiguangshen"] = "yiguangshen"var chan1 chan stringchan1 = make(chan string, 1)chan1 <- "mellowchen"close(chan1)for index, value := range i1 {print(index, value)}for index, value := range slice {print(index, value)}for key, value := range map1 {print(key, value)}for value := range chan1 {print(value)}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/92707.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/92707.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/92707.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codeforces Round 967 (Div. 2) D. Longest Max Min Subsequence

假设我们要选a[j]为答案数组b[i]&#xff0c;从i从1~m&#xff08;m为a数组中不同数的个数&#xff09;建立一个suf数组&#xff0c;代表以i开头的后缀有多少个不同且在b[1~i-1]中未出现过的的个数&#xff0c;预处理suf&#xff0c;发现后续我们怎么选数改变suf&#xff0c;su…

Linux运维新手的修炼手扎之第27天

mysql服务1 主从复制集群&#xff1a;多主机集群【复制】负载过大解决方案&#xff1a;横向扩展[增加服务器节点分散负载]、纵向扩展[提升单机硬件性能]复制工作原理&#xff1a;前提&#xff1a;基础数据一样&#xff0c;主节点上有同步数据用的账号主角色【二进制日志、binlo…

【Linux】Linux增删改查命令大全(附频率评级)

Linux增删改查命令大全&#xff08;附频率评级&#xff09;* 《Linux命令全景手册&#xff1a;增删改查全场景解析&#xff08;含136个高频命令&#xff09;》 按使用频率★分级 | 测试/运维/开发均适用 | 附思维导图下载一、命令全景表&#xff08;增删改查频率评级&#xff0…

SwiftUI 登录页面键盘约束冲突与卡顿优化全攻略

网罗开发&#xff08;小红书、快手、视频号同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

建筑物实例分割数据集-9,700 张图片 城市规划与发展 灾害评估与应急响应 房地产市场分析 智慧城市管理 地理信息系统(GIS) 环境影响评估

建筑物实例分割数据集-9,700 张图片&#x1f4e6; 已发布目标检测数据集合集&#xff08;持续更新&#xff09;&#x1f3e2; 建筑物实例分割数据集介绍&#x1f4cc; 数据集概览包含类别&#x1f3af; 应用场景&#x1f5bc; 数据样本展示使用建议&#x1f31f; 数据集特色&am…

LeetCode 刷题【36. 有效的数独】

36. 有效的数独 自己做 解&#xff1a;多层for class Solution { public:bool isValidSudoku(vector<vector<char>>& board) {int hight board.size(); //长if (hight 0)return true;int wide board[0].size(); //宽//判断一行是否出现重复bool…

Java 日志从入门到精通:告别日志混乱

作为一名 Java 开发者&#xff0c;你是否曾在生产环境故障排查时面对过这样的困境&#xff1a;系统报错却找不到关键日志&#xff0c;日志文件大到无法打开&#xff0c;或者日志内容杂乱无章根本无法定位问题&#xff1f;日志作为系统运行的 “黑匣子”&#xff0c;其重要性不言…

系统开发 Day1

前端开发 目的&#xff1a; 开发一个平台&#xff08;网站&#xff09; - 前端开发&#xff1a;HTML CSS JavaScript - web框架&#xff1a;接受请求和处理 - MySQL数据库&#xff1a;存储数据的地方快速上手&#xff1a;基于Flask Web框架快速搭建一个网站 深度学习&#xff…

机器视觉任务(目标检测、实例分割、姿态估计、多目标跟踪、单目标跟踪、图像分类、单目深度估计)常用算法及公开数据集分享

本文按目标检测、实例分割、姿态估计、多目标跟踪、单目标跟踪、图像分类、单目深度估计七个任务分类&#xff0c;融合数据集介绍、评价指标及推荐算法&#xff0c;方便查阅&#xff1a; 一、目标检测 目标检测任务需定位图像中目标的边界框&#xff08;bounding box&#xff0…

MongoTemplate中setOnInsert与set方法的深度解析

MongoTemplate中setOnInsert与set方法的深度解析 在Spring Data MongoDB的MongoTemplate中&#xff0c;setOnInsert和set方法都是在更新文档时使用的&#xff0c;但它们在处理upsert操作&#xff08;即&#xff0c;如果文档不存在则插入&#xff0c;存在则更新&#xff09;时扮…

利用OJ判题的多语言优雅解耦方法深入体会模板方法模式、策略模式、工厂模式的妙用

在线评测系统&#xff08;Online Judge, OJ&#xff09;的核心是判题引擎&#xff0c;其关键挑战在于如何高效、安全且可扩展地支持多种编程语言。在博主的项目练习过程中&#xff0c;借鉴了相关设计模式实现一种架构设计方案&#xff0c;即通过组合运用模板方法、策略、工厂等…

[FOC电机控制]霍尔传感器于角度问题

如果电机有1对极(p1&#xff0c;那么每旋转一圈的机械角度&#xff0c;电气角度会转动一圈&#xff08;360&#xff09;。如果电机有2对极(p2&#xff0c;那么每旋转一圈的机械角度&#xff0c;电气角度会转动两圈&#xff08;720&#xff09;。

阿里云 Flink

阿里云 Flink 是阿里云基于Apache Flink打造的企业级实时计算平台&#xff0c;旨在为用户提供高效、稳定、易用的流处理与批处理能力&#xff0c;帮助企业快速构建实时数据处理链路&#xff0c;支撑实时业务决策。核心特性流批一体计算继承 Apache Flink “流批一体” 的核心优…

企业级高性能web服务器

1 web服务基础 1.1 正常情况的单次web服务访问流程&#xff1a; 正常情况下&#xff0c;单次 Web 服务访问流程从用户在客户端发起请求开始&#xff0c;到最终在客户端展示内容结束&#xff0c;涉及客户端、网络传输、服务器端等多个环节&#xff0c;以下是详细过程&#xff…

免费PDF编辑软件 pdf24-creator 及其安装包

最近发现了一款还算是不错的PDF编辑和阅读软件 pdf24-creator&#xff0c;官方下载网站为&#xff1a;https://tools.pdf24.org/zh/creator&#xff0c;但是官方下载如果没有魔法的话&#xff0c;下载速度很慢&#xff0c;比百度网盘下载还满&#xff0c;因此我把它分享到网盘。…

openvela之ADB

ADB&#xff08;Android Debug Bridge&#xff09;是一款功能丰富的命令行工具&#xff0c;旨在实现开发工作站与设备&#xff08;如模拟器、实体设备&#xff09;之间的通信。通过 ADB&#xff0c;开发者可以便捷地在设备上执行命令、传输文件、调试应用等。本文将详细介绍 AD…

如何控制需求交付节奏

有效控制需求的交付节奏&#xff0c;其核心在于将产品开发过程从一个不可预测的、时快时慢的混乱状态&#xff0c;转变为一套产出稳定、流程顺畅、步调可持续的系统化交付机制。要成功构建这套机制&#xff0c;实现有节奏的价值交付&#xff0c;必须综合运用五大关键策略&#…

汇编中常用寄存器介绍

X86-32位寄存器 4个数据寄存器&#xff1a;EAX、EBX、ECX和EDX; 2个变址和指针寄存器&#xff1a;ESI和EDI; 2个指针寄存器&#xff1a;ESP和EBP; 1个指令指针寄存器&#xff1a;EIP; 6个段寄存器&#xff1a;ES、CS、SS、DS、FS和GS; 1个标志寄存器&#xff1a;EFlags。 在X8…

SOMGAN:用自组织映射改善GAN的模式探索能力

论文信息 论文题目:Improving mode exploring capability ofgenerative adversarial nets by self-organizing map(利用自组织映射提高生成对抗网络的模式探索能力) 期刊:Neurocomputing 摘要:生成对抗网络(GANs)的出现将生成模型的研究推向了一个新的高潮。支持这一进步…

《汇编语言:基于X86处理器》第12章 复习题和练习

本篇记录了《汇编语言&#xff1a;基于X86处理器》第12章 复习题和练习的笔记。12.6复习题和练习12.6.1 简答题1.假设有二进制浮点数1101.01101&#xff0c;如何将其表示为十进制分数之和?答&#xff1a;1101.01101(1x)(1x)(0x)(1x)(0x)(1x)(1x)(1x)(1x) 13.406252.为什么十进…