Go && java语言对比
前言
近期在学习go语言,这里简单总结一下它和java语言的不同之处,以便加深印象
1、静态类型 + 短变量自动推导
go语言是静态语言,但在编写时可以不显示指定类型,而根据短变量声明赋的值来决定类型
package main import "fmt" func main() { // 短变量声明(函数内):自动推导类型 name := "Go" // string age := 10 // int pi := 3.14 // float64 isOk := true // bool // var 声明也支持类型推导 var score = 99.5 // float64 fmt.Printf("name: %T, age: %T, pi: %T\n", name, age, pi) }
2、类型后置
go的类型(变量、函数返回值、指针、切片)是后置的,跟java python有很大区别,要习惯
package main import "fmt" // 函数返回值类型后置 func add(a int, b int) int { return a + b } // 多返回值类型后置 func divide(a, b int) (int, error) { if b == 0 { return 0, fmt.Errorf("division by zero") } return a / b, nil } func main() { // 变量类型后置 var num int = 10 var ptr *int = &num // 指针类型后置 fmt.Println("num:", num, "ptr:", *ptr) }
3、没有class,只有struct
go中没有类这个概念,仅有struct结构体的概念,可以用结构体 + 方法 + 组合实现面向对象,而非继承
package main import "fmt" // 定义结构体(替代 class) type Person struct { Name string Age int } func main() { // 初始化结构体 p := Person{Name: "Alice", Age: 25} fmt.Printf("Person: %+v\n", p) }
4、方法绑定到struct(Receiver)
没有类便没有成员方法这个概念,但可以将方法绑定到struct里,实现类似成员方法的功能
package main import "fmt" type Person struct { Name string Age int } // 值接收者:不修改原对象 func (p Person) SayHello() { fmt.Printf("Hello, I'm %s\n", p.Name) } // 指针接收者:修改原对象 func (p *Person) Birthday() { p.Age++ } func main() { p := Person{Name: "Bob", Age: 30} p.SayHello() p.Birthday() fmt.Printf("After birthday: %+v\n", p) // Age: 31 }
5、非侵入式接口(鸭子类型)
go的接口不需要显示(如java的implements关键字)实现,如果一个结构体绑定的方法包含了接口的所有方法,便可认为实现了接口,可以利用接口的多态特性
package main import "fmt" // 定义接口 type Speaker interface { Speak() string } // 定义 Dog 结构体 type Dog struct{} // Dog 实现 Speak() 方法 func (d Dog) Speak() string { return "Woof!" } // 定义 Cat 结构体 type Cat struct{} // Cat 实现 Speak() 方法 func (c Cat) Speak() string { return "Meow!" } // 多态:接收 Speaker 接口 func MakeSpeak(s Speaker) { fmt.Println(s.Speak()) } func main() { dog := Dog{} cat := Cat{} MakeSpeak(dog) // Woof! MakeSpeak(cat) // Meow! }
6、多返回值 + error错误处理
go的方法是支持多返回值的,一般会另外返回个Error来确定是否执行正常
package main import ( "errors" "fmt" ) // 多返回值:(结果, error) func Divide(a, b int) (int, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil } func main() { res, err := Divide(10, 2) if err != nil { fmt.Println("Error:", err) return } fmt.Println("Result:", res) // 5 // 测试错误情况 res, err = Divide(10, 0) if err != nil { fmt.Println("Error:", err) // Error: division by zero return } }
7、goroutine + channel实现并发
go可以很方便的实现并发,利用go语句就能触发并发操作,利用channel可以实现协程间的通信,没有线程池概念,但可通过GMP调度器做线程管理
package main import ( "fmt" "time" ) // goroutine 示例 func sayHello(name string) { fmt.Printf("Hello, %s!\n", name) } func main() { // 启动 5 个 goroutine for i := 0; i < 5; i++ { go sayHello(fmt.Sprintf("Goroutine %d", i)) } // 等待 goroutine 执行(实际项目用 sync.WaitGroup) time.Sleep(100 * time.Millisecond) fmt.Println("Main done") }
8、go是只有值传递的,但是go中有指针,可以通过指针实现引用传递
package main import "fmt" // 值传递:拷贝参数 func modifyValue(x int) { x = 100 } // 指针传递:修改原对象 func modifyPointer(x *int) { *x = 100 } func main() { a := 10 modifyValue(a) fmt.Println("After modifyValue:", a) // 10(未修改) modifyPointer(&a) fmt.Println("After modifyPointer:", a) // 100(已修改) }
9、首字母大小写控制可见性
go没有显示的静态修饰符,其方法和变量,首字母大小的可视为导出的,可被外部包使用,首字母小写的,则只能被内部包使用
// 文件名:visibility.go package main import "fmt" // 包级变量(类似 static) var PackageVar = "I'm visible outside" // 首字母大写:导出(public) func ExportedFunc() { fmt.Println("ExportedFunc: visible outside") } // 首字母小写:私有(private) func privateFunc() { fmt.Println("privateFunc: only visible in this package") } func main() { ExportedFunc() privateFunc() fmt.Println(PackageVar) }
10、用切片替代List
go没有list的概念,其切片便对应java中的list,且可以和数组方便的做转换
package main import "fmt" func main() { // 1. 数组(固定长度) arr := [3]int{1, 2, 3} fmt.Println("Array:", arr) // 2. 切片(动态长度,类似 List) slice := []int{1, 2, 3} slice = append(slice, 4, 5) // 追加元素 fmt.Println("Slice:", slice) // 3. 数组转切片 sliceFromArr := arr[:] fmt.Println("Slice from array:", sliceFromArr) // 4. 切片截取(类似 subList) subSlice := slice[1:3] fmt.Println("Sub-slice:", subSlice) }
11、泛型
package main import "fmt" // 泛型函数:支持任意类型 func PrintSlice[T any](s []T) { for _, v := range s { fmt.Println(v) } } func main() { intSlice := []int{1, 2, 3} stringSlice := []string{"a", "b", "c"} PrintSlice(intSlice) PrintSlice(stringSlice) }
12、defer
go的defer会在函数退出前自动执行,代码更简洁
package main import ( "fmt" "os" ) func main() { file, err := os.Open("test.txt") if err != nil { fmt.Println("Error:", err) return } defer file.Close() // 函数退出前自动关闭文件 fmt.Println("File opened successfully") }
13、无需break的switch
go的switch支持多条件、类型switch,且默认不穿透
package main import "fmt" func main() { // 1. 多条件 switch num := 2 switch num { case 1, 3, 5: fmt.Println("Odd") case 2, 4, 6: fmt.Println("Even") default: fmt.Println("Other") } // 2. 类型 switch var x interface{} = 10 switch v := x.(type) { case int: fmt.Printf("Int: %d\n", v) case string: fmt.Printf("String: %s\n", v) default: fmt.Println("Unknown type") } }

浙公网安备 33010602011771号