从 Golang中 method has pointer receiverd 异常去理解interface机制

在Golang中第一次使用interface 遇到了一个有意思的问题:

method has pointer receiverd

这个问题很普遍,所以在此记录先来。
先看以下例子:

package main
import (
    "fmt"
)

// notifier is an interface that defined
// type behavior.

type notifier interface {
    notify()
}

// user defines a user in the program.

type user struct {
    name  string
    email string
}

// notify implements a method with a poi
func (u *user) notify() {   
    fmt.Printf("Sending user email to %s“,u.name)
}

// main is the entry point for the appli
func main() {

    // Create a value of type User and s
    u := user{"Bill", "bill@email.com"}

    sendNotification(u)
}
func sendNotification(n notifier) {
     n.notify()
}

运行以上代码,会得到一个这样的错误:

./listing36.go:32: cannot use u (type user) as type
                   notifier in argument to sendNotification:
user does not implement notifier (notify method has pointer receiver)

为了解决这个问题,首先得先了解一下Golang

### Golang 中 `atomic.Pointer` 的用法与实现 在 Golang 的 `sync/atomic` 包中,并不存在直接命名为 `atomic.Pointer` 的类型或方法[^1]。然而,Golang 的 `sync/atomic` 包确实支持对指针类型的原子操作,例如通过 `unsafe.Pointer` 类型来实现类似的功能。以下是对原子指针操作的详细说明及其实现示例。 #### 1. 原子指针操作的支持 Golang 的 `sync/atomic` 包允许对 `unsafe.Pointer` 类型进行原子操作,包括加载 (`Load`)、存储 (`Store`) 和比较交换 (`CompareAndSwap`)。这些操作可以用来实现对任意指针类型的原子更新。以下是相关的原子操作函数: - **`LoadPointer(ptr *unsafe.Pointer) unsafe.Pointer`**:原子地加载并返回存储在 `ptr` 中的值。 - **`StorePointer(ptr *unsafe.Pointer, val unsafe.Pointer)`**:原子地将 `val` 存储到 `ptr` 中。 - **`CompareAndSwapPointer(ptr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)`**:如果 `*ptr` 等于 `old`,则原子地将其替换为 `new` 并返回 `true`;否则返回 `false`。 #### 2. 使用 `unsafe.Pointer` 实现原子指针操作 由于 `sync/atomic` 包中的原子操作仅支持有限的内置类型(如 `int32`、`int64`、`uint32`、`uint64` 等)以及 `unsafe.Pointer`,因此需要借助 `unsafe.Pointer` 来操作自定义类型的指针。以下是一个使用 `unsafe.Pointer` 实现原子指针操作的示例: ```go package main import ( "fmt" "sync" "sync/atomic" "unsafe" ) type MyStruct struct { Field int } func main() { var ptr unsafe.Pointer // 原子指针变量 // 创建一个初始结构体实例 s1 := &MyStruct{Field: 1} ptr = unsafe.Pointer(s1) // 创建另一个结构体实例 s2 := &MyStruct{Field: 2} // 原子更新指针 atomic.StorePointer(&ptr, unsafe.Pointer(s2)) // 原子加载指针 loadedPtr := atomic.LoadPointer(&ptr) loadedStruct := (*MyStruct)(loadedPtr) fmt.Println("Loaded struct:", loadedStruct.Field) // 比较并交换指针 swapped := atomic.CompareAndSwapPointer(&ptr, unsafe.Pointer(s2), unsafe.Pointer(s1)) if swapped { fmt.Println("Swap successful") } else { fmt.Println("Swap failed") } // 再次加载指针以验证结果 loadedPtrAfterSwap := atomic.LoadPointer(&ptr) loadedStructAfterSwap := (*MyStruct)(loadedPtrAfterSwap) fmt.Println("Loaded struct after swap:", loadedStructAfterSwap.Field) } ``` #### 3. 注意事项 - 使用 `unsafe.Pointer` 时需格外小心,因为不正确的转换可能导致程序崩溃或未定义行为[^1]。 - `sync/atomic` 包并未提供针对指针类型的加法操作(如 `AddPointer`),这是因为指针加法通常涉及内存地址计算,容易引发安全问题[^3]。 - 在并发环境中,原子操作是确保数据一致性的关键工具,但应避免过度依赖它们,以免降低代码可读性[^4]。 #### 4. 示例解释 上述代码展示了如何使用 `sync/atomic` 包对指针类型进行原子操作: - 使用 `atomic.StorePointer` 更新指针值。 - 使用 `atomic.LoadPointer` 加载当前指针值。 - 使用 `atomic.CompareAndSwapPointer` 进行条件更新。 这些操作适用于需要在多线程环境下安全地管理指针引用的场景。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值