Go与Java语法对比(二)

数组

Java:在Java语言中,数组声明格式如下:

// 声明一个长度为5, 元素类型为int的数组
int[] nums = new int[5];
// 对数组第一个元素进行赋值
nums[0] = 1;
// 访问数组的第一个元素
int num = nums[0];
// 声明的同时初始化数组
int[] nums = new int[] {1, 2, 3, 4, 5};
// 声明并初始化数组可以使用以下简化的语法
int[] nums = {1, 2, 3, 4, 5};
// 获取数组的长度
int length = nums.length;
// 创建多维数组
int[][] matrix = new int[2][2];

Go:在Go语言中,数组声明格式如下:

// 声明一个长度为5, 元素类型为int的数组
var nums [5]int
// 对数组第一个元素进行赋值
nums[0] = 1
// 访问数组的第一个元素
var num = nums[0]
// 声明的同时初始化数组
var nums = [5]int {1,2,3,4,5}
// 简洁写法
nums := [5]int {1,2,3,4,5}
// 数组的长度声明可以省略, 用 ... 代替, 编译器会自动计算长度
nums := [...]int {1,2,3,4,5}
// 获取数组的长度
length := len(nums)
// 创建多维数组
var matrix [2][2]int
// 和Java语言不同的是, Go语言中的数组是值类型, 不是引用类型
// 将数组赋值给一个新变量, 新变量会得到一个原始数组的副本, 对新变量的修改不会影响原始数组
nums2 := nums
nums2[0] = 2
// 此时会输出1
fmt.Println(nums[0])

切片(Go独有)

Java语言和Go语言中的数组都是固定长度的,一旦声明后不能再修改数组长度,实际使用时不够灵活,所以Java中专门提供了集合来解决数组长度限制的问题。而在Go语言中,在数组之上还建立了一种方便、灵活且功能强大的包装——切片(Slice)。切片是一种动态数组的抽象,它提供了对底层数组的部分或全部连续元素的引用。切片相比于数组具有更灵活的长度和容量,并且支持动态增长。

// 切片是对数组中一段连续元素的引用
// 先创建一个长度为5的数组
numArr := [5]int {1,2,3,4,5}
// 创建引用数组索引2到4的切片, 切片nums的值为[3,4]
nums := numArr[2:4]
// 切片是对原数组的引用, 对切片的修改会反映到原数组中, 此时数组numArr变为[1,2,4,4,5]
nums[0] = 4
// 此时会输出4
fmt.Println(numArr[2])
// 也可以直接声明一个切片
var nums []int
// 声明的同时进行初始化切片
nums := []int {1,2,3,4,5}
// 切片除了有长度属性表示切片中的元素数外, 还有容量属性, 表示从切片索引开始的引用数组中的元素数
// 切片长度为2
length := len(nums)
// 切片是从引用数组索引2开始的, 所以容量是3
capacity := cap(nums)
// 还可以使用make([]T,len,cap)函数创建切片, 此时会为切片中的元素进行自动初始化, int类型的元素默认值为0, 此时切片中的内容为[0,0,0,0,0]
nums := make([]int, 5, 5)
// 容量可省略, 默认值为切片长度
nums := make([]int, 5)
// 使用append函数可以向切片末尾添加一个或多个元素, append函数会返回一个新的切片, 原始切片保持不变
// 此时新的切片变为[0,0,0,0,0,1]
nums = append(nums, 1)
// 可以一次添加多个元素, 此时新的切片变为[0,0,0,0,0,1,2,3,4,5]
nums = append(nums, 2, 3, 4, 5)
// 可以使用... 运算符将一个切片添加到另一个切片中
nums1 := []int{1,2}
nums2 := []int{3,4,5}
// 此时nums中元素为[1,2,3,4,5]
nums := append(nums1, nums2...)

Map / map

Java:在Java语言中,Map是一个接口,使用时需要创建一个Map接口的实现类:

Map<String, String> map = new HashMap<>();
// 添加一个键值对
map.put("name", "张三");
// 根据键获取对应的值
String name = map.get("name");
// 判断键是否存在
boolean exist = map.containsKey("name");
// 删除一个键值对
map.remove("name");
// 获取map的长度
int length = map.size();

Go:在Go语言中,map是一种内置的数据类型,直接通过map关键字进行声明和使用:

// map 的零值是 nil, 必须使用 make 函数初始化
m := make(map[string]string)
// 可以声明的同时进行初始化
m := map[string]string {"name": "张三"}
// 添加一个键值对
m["name"] = "张三"
// 根据键获取对应的值
name := m["name"]
// 判断键是否存在, 如果 exist 是 true 表示 key 存在
value, exist := m["name"]
// 删除一个键值对
delete(m, "name")
// 获取map的长度
length := len(m)

指针(Go独有)

Go:在Go语言中,指针是一种特殊的数据类型,用于存储变量的内存地址。指针可以用于直接访问和修改变量的值,而不是通过变量本身进行操作:

// 声明一个整数变量和一个指向整数的指针
num := 10
var ptr *int = &num
// 此处会打印num变量的地址
fmt.Println(ptr)
// 解引用指针, 获取指针指向的值, 此处会输出10
fmt.Println(*ptr)
// 修改指针指向的值, 指向的num变量也会被修改
*ptr = 20
// 此处会输出20
fmt.Println(num)
// 使用new函数创建指针
anotherPtr := new(int)
*anotherPtr = 30
// 此处会输出30
fmt.Println(*anotherPtr)

类 / 结构体

Java:在Java语言中,数据的封装是通过类来进行实现:

public class Person {

	private String name;

	private int age;

	public Person() {
		super();
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

// 使用无参构造器创建对象
Person person = new Person();
// 使用有参构造器创建对象
Person person = new Person("张三", 18);
// 访问对象的属性
int age = person.age;
// 调用对象的方法
person.setAge(20);
int age = person.getAge();

Go:在Go语言中,数据的封装是通过结构体来进行实现:

type Person struct {
	name string
	age int
}
// Go语言中, 可以在func关键字和函数名中间加入接收器, 来为结构体绑定方法, 通过这种方式可以实现和Java语言中类相似的行为
func (person *Person) GetName() string {
	return person.name
}

func (person *Person) SetName(name string) {
	person.name = name
}

func (person *Person) GetAge() int {
	return person.age
}

func (person *Person) SetAge(age int) {
	person.age = age
}

// 创建结构体
person := Person{}
// 创建结构体并赋值
person := Person{"张三", 18}
// 赋值时可以指定名称, 这样属性赋值的顺序可以与结构体定义顺序不一致
person := Person{age: 18, name: "张三"}
// 访问结构体的属性
person.age = 20
age := person.age
// 创建指向结构体的指针
person := &Person{"张三", 18}
// 使用指针访问结构体的属性
age := (*person).age
// Go语言可以省略显式的解引用
age := person.age
// 访问绑定了结构体的方法
person.SetAge(20)
age := person.GetAge()

接口

Java:在Java语言中,实现接口必须使用 implement 关键字,来显式地声明该类实现了接口:

// 定义一个接口
public interface Shape {
	double getArea();
}

// 实现接口的类
public class Circle implements Shape {
	
	private double radius;

	public Circle(double radius) {
		this.radius = radius;
	}

	@Override
	public double getArea() {
		return Math.PI * radius * radius;
	}
}

// 使用接口
Shape shape = new Circle(5.0);
System.out.println("Area: " + shape.getArea());

Go:在Go语言中,不要显示声明实现接口,如果一个类型定义了与接口中定义的所有方法相匹配的方法,那么该类型隐式地满足该接口。这种方式称为结构体的隐式实现:

// 定义一个接口
type Shape interface {
	getArea() float64
}

// 实现接口的结构体
type Circle struct {
	radius float64
}

func (c Circle) getArea() float64 {
	return math.Pi * c.radius * c.radius
}

// 使用接口
var shape Shape = Circle{radius: 5.0}
fmt.Println("Area:", shape.getArea())

异常 / 错误

Java:在Java语言中,异常处理通过try-catch-finally语句块来实现,可以使用try块来包含可能抛出异常的代码,然后使用catch块来捕获并处理异常,最后可以使用finally块来执行清理操作:

public static void main(String[] args) {
	try {
		int result = divide(10, 0);
		System.out.println("Result: " + result);
	} catch (ArithmeticException e) {
		System.out.println("Error: " + e.getMessage());
	}
}

// 执行除法运算的函数
public static int divide(int dividend, int divisor) {
	if (divisor == 0) {
		// 抛出一个ArithmeticException异常,表示除数为零的错误
		throw new ArithmeticException("Division by zero");
	}
	return dividend / divisor;
}

Go:在Go语言中,错误处理通过返回值来实现,函数可以返回一个额外的错误值,通常是最后一个返回值,以指示函数是否成功执行。调用函数时,需要检查返回的错误值并采取相应的处理措施:

func main() {
	result, err := divide(10, 0)
	if err != nil {
		fmt.Println("Error:", err.Error())
	} else {
		fmt.Println("Result:", result)
	}
}

// 执行除法运算的函数
func divide(dividend, divisor int) (int, error) {
	if divisor == 0 {
		// 使用errors.New函数创建一个新的错误值,表示除数为零的错误
		return 0, errors.New("Division by zero")
	}
	return dividend / divisor, nil
}

函数式接口 /头等函数

Java:在Java语言中,方法不能直接当做参数传递给其他方法,不过Java可以定义一个函数式接口,其中只包含一个方法,然后可以使用匿名内部类 / Lambda表达式方式创建实例来表示函数,从而做到类似的效果:

// 定义一个函数式接口
@FunctionalInterface
public interface MathOperation {
	int operate(int a, int b);
}

public static void main(String[] args) {
	// 定义一个接口实例,使用Lambda表达式创建匿名函数
	MathOperation add = (a, b) -> a + b;
	MathOperation subtract = (a, b) -> a - b;

	// 调用operate函数执行数学操作,并输出结果
	System.out.println("Addition: " + operate(5, 3, add));
	System.out.println("Subtraction: " + operate(5, 3, subtract));
}

// 执行数学操作的函数
public static int operate(int a, int b, MathOperation operation) {
	// 调用接口实例的方法来执行函数
	return operation.operate(a, b);
}

Go:在Go语言中,函数被视为一等公民,可以像其他值(如整数、字符串等)一样被赋值给变量、作为参数传递给其他函数或从函数中返回:

// 定义一个函数
type MathOperation func(a, b int) int

func main() {
	// 定义函数类型的变量,使用匿名函数赋值
	add := func(a, b int) int {
		return a + b
	}
	subtract := func(a, b int) int {
		return a - b
	}

	// 调用operate函数执行数学操作,并输出结果
	fmt.Println("Addition:", operate(5, 3, add))
	fmt.Println("Subtraction:", operate(5, 3, subtract))
}

// 执行数学操作的函数
func operate(a, b int, operation MathOperation) int {
	// 调用函数类型变量来执行函数
	return operation(a, b)
}
文章作者: Hakurei
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Zero
后端 Golang Java
喜欢就支持一下吧