Go 语言独特特性
Go 语言独特特性
Go 中的指针
基本概念
// Go指针
var x int = 42
var p *int = &x // p是指向x的指针
fmt.Println(*p) // 解引用,输出42
*p = 21 // 通过指针修改x的值
fmt.Println(x) // 输出21
// 创建指针的另一种方式
y := new(int) // 创建一个指向int零值的指针
*y = 100 // 设置值
对比其他语言:
# Python没有直接的指针概念,但有对象引用
x = 42
y = x # y引用与x相同的值
y = 21 # 修改y不影响x
print(x) # 输出42
# 对于可变对象,行为类似指针
list1 = [1, 2, 3]
list2 = list1 # list2引用与list1相同的列表
list2.append(4) # 修改list2也会影响list1
print(list1) # 输出[1, 2, 3, 4]
// Java没有直接的指针,但有对象引用
Integer x = 42; // Integer是对象,存储在堆上
Integer y = x; // y引用与x相同的对象
y = 21; // 创建新对象,y指向新对象
System.out.println(x); // 输出42
// 对于对象,行为类似指针
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
ArrayList<Integer> list2 = list1; // list2引用与list1相同的对象
list2.add(2);
System.out.println(list1); // 输出[1, 2]
// C#有引用类型和值类型,以及ref参数
int x = 42; // 值类型
int y = x; // 复制值
y = 21; // 修改y不影响x
Console.WriteLine(x); // 输出42
// 使用ref参数可以实现类似指针的行为
void Modify(ref int a) {
a = 100;
}
int z = 42;
Modify(ref z);
Console.WriteLine(z); // 输出100
// 对于引用类型,行为类似指针
List<int> list1 = new List<int> { 1, 2, 3 };
List<int> list2 = list1; // list2引用与list1相同的对象
list2.Add(4);
Console.WriteLine(string.Join(", ", list1)); // 输出"1, 2, 3, 4"
指针的用途
// Go中指针的常见用途
// 1. 修改函数外部的变量
func increment(n *int) {
*n++
}
count := 10
increment(&count)
fmt.Println(count) // 输出11
// 2. 避免复制大型结构体
type LargeStruct struct {
Data [1024]int
}
func process(ls *LargeStruct) {
// 处理结构体但不复制它
ls.Data[0] = 42
}
ls := LargeStruct{}
process(&ls)
// 3. 实现数据结构
type Node struct {
Value int
Next *Node // 指向下一个节点的指针
}
错误处理
错误值 vs. 异常
// Go的错误处理 - 返回错误值
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为零")
}
return a / b, nil
}
// 调用并处理错误
result, err := divide(10, 0)
if err != nil {
fmt.Println("错误:", err)
return
}
fmt.Println("结果:", result)
// 自定义错误
type DivisionError struct {
Dividend float64
Divisor float64
}
func (e *DivisionError) Error() string {
return fmt.Sprintf("不能将%.2f除以%.2f", e.Dividend, e.Divisor)
}
func safeDivide(a, b float64) (float64, error) {
if b == 0 {
return 0, &DivisionError{a, b}
}
return a / b, nil
}
对比其他语言:
# Python的异常处理
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
# 使用try-except捕获异常
try:
result = divide(10, 0)
print("结果:", result)
except ValueError as e:
print("错误:", e)
# 自定义异常
class DivisionError(Exception):
def __init__(self, dividend, divisor):
self.dividend = dividend
self.divisor = divisor
super().__init__(f"不能将{dividend}除以{divisor}")
def safe_divide(a, b):
if b == 0:
raise DivisionError(a, b)
return a / b
// Java的异常处理
public static double divide(double a, double b) throws ArithmeticException {
if (b == 0) {
throw new ArithmeticException("除数不能为零");
}
return a / b;
}
// 使用try-catch捕获异常
try {
double result = divide(10, 0);
System.out.println("结果: " + result);
} catch (ArithmeticException e) {
System.out.println("错误: " + e.getMessage());
}
// 自定义异常
class DivisionException extends Exception {
private double dividend;
private double divisor;
public DivisionException(double dividend, double divisor) {
super(String.format("不能将%.2f除以%.2f", dividend, divisor));
this.dividend = dividend;
this.divisor = divisor;
}
}
public static double safeDivide(double a, double b) throws DivisionException {
if (b == 0) {
throw new DivisionException(a, b);
}
return a / b;
}
// C#的异常处理
public static double Divide(double a, double b)
{
if (b == 0)
{
throw new DivideByZeroException("除数不能为零");
}
return a / b;
}
// 使用try-catch捕获异常
try
{
double result = Divide(10, 0);
Console.WriteLine($"结果: {result}");
}
catch (DivideByZeroException e)
{
Console.WriteLine($"错误: {e.Message}");
}
// 自定义异常
public class DivisionException : Exception
{
public double Dividend { get; }
public double Divisor { get; }
public DivisionException(double dividend, double divisor)
: base($"不能将{dividend}除以{divisor}")
{
Dividend = dividend;
Divisor = divisor;
}
}
public static double SafeDivide(double a, double b)
{
if (b == 0)
{
throw new DivisionException(a, b);
}
return a / b;
}
错误处理最佳实践
// Go错误处理最佳实践
// 1. 尽早返回错误
func processFile(path string) error {
file, err := os.Open(path)
if err != nil {
return fmt.Errorf("打开文件失败: %w", err)
}
defer file.Close()
// 处理文件...
return nil
}
// 2. 使用defer确保资源释放
func copyFile(src, dst string) error {
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("打开源文件失败: %w", err)
}
defer srcFile.Close()
dstFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("创建目标文件失败: %w", err)
}
defer dstFile.Close()
_, err = io.Copy(dstFile, srcFile)
if err != nil {
return fmt.Errorf("复制文件失败: %w", err)
}
return nil
}
// 3. 错误包装 (Go 1.13+)
func readConfig(path string) ([]byte, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("读取配置文件 %s 失败: %w", path, err)
}
return data, nil
}
并发模型
Goroutines
// Go的并发 - Goroutines
func sayHello() {
fmt.Println("Hello, Gopher!")
}
// 启动一个goroutine
go sayHello()
// 带参数的goroutine
go func(name string) {
fmt.Printf("Hello, %s!\n", name)
}("Gopher")
// 等待goroutine完成
time.Sleep(100 * time.Millisecond)
// 更好的方式 - 使用WaitGroup
var wg sync.WaitGroup
wg.Add(1) // 添加一个等待的goroutine
go func() {
defer wg.Done() // 完成时通知WaitGroup
fmt.Println("Working...")
}()
wg.Wait() // 等待所有goroutine完成
对比其他语言:
# Python的线程和异步
import threading
import asyncio
# 使用线程
def say_hello():
print("Hello, Pythonista!")
thread = threading.Thread(target=say_hello)
thread.start()
thread.join() # 等待线程完成
# 使用asyncio (Python 3.5+)
async def async_hello():
print("Hello, async Python!")
async def main():
await async_hello()
asyncio.run(main()) # Python 3.7+
// Java的线程和并发
// 使用Thread
Thread thread = new Thread(() -> {
System.out.println("Hello, Java!");
});
thread.start();
try {
thread.join(); // 等待线程完成
} catch (InterruptedException e) {
e.printStackTrace();
}
// 使用ExecutorService
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
System.out.println("Hello from ExecutorService!");
});
executor.shutdown();
// 使用CompletableFuture (Java 8+)
CompletableFuture.runAsync(() -> {
System.out.println("Hello from CompletableFuture!");
}).join();
// C#的线程和异步
// 使用Thread
Thread thread = new Thread(() => {
Console.WriteLine("Hello, C#!");
});
thread.Start();
thread.Join(); // 等待线程完成
// 使用Task
Task task = Task.Run(() => {
Console.WriteLine("Hello from Task!");
});
task.Wait(); // 等待任务完成
// 使用async/await
public async Task SayHelloAsync()
{
await Task.Delay(100); // 模拟异步操作
Console.WriteLine("Hello, async C#!");
}
// 调用异步方法
await SayHelloAsync();
通道和 Select
// Go的通道 (Channels)
// 创建通道
ch := make(chan string) // 无缓冲通道
bufferedCh := make(chan int, 10) // 缓冲通道
// 发送和接收
go func() {
ch <- "hello" // 发送到通道
}()
msg := <-ch // 从通道接收
// 关闭通道
close(ch)
// 遍历通道
for msg := range ch {
fmt.Println(msg)
}
// select语句 - 多通道操作
select {
case msg1 := <-ch1:
fmt.Println("收到来自ch1的消息:", msg1)
case msg2 := <-ch2:
fmt.Println("收到来自ch2的消息:", msg2)
case ch3 <- "hello