Преобразование **T в *unsafe.Pointer в Go

Как преобразовать переменную типа **T в *unsafe.Pointer?

Пример ниже даст ошибку компиляции:

не может преобразовать &ptr (тип **s) в тип *unsafe.Pointer

package main

import (
    "sync/atomic"
    "unsafe"
)

type s struct {
    value int
}

func main(){
    var ptr *s
    a := &s{42}

    old := ptr
    atomic.CompareAndSwapPointer(
        (*unsafe.Pointer)(&ptr), // &unsafe.Pointer(ptr)
        unsafe.Pointer(old),
        unsafe.Pointer(a))
}

Если я переключу (*unsafe.Pointer)(&ptr) на &unsafe.Pointer(ptr), я получу эту ошибку компиляции:

не может получить адрес unsafe.Pointer(ptr)

Пс. Я решил сделать пример с sync/atomic, потому что это одна из ситуаций, когда вам действительно нужно выполнить такое преобразование.

Изменить

Одним из неправильных решений было бы использование временной переменной:

up := unsafe.Pointer(ptr)
atomic.CompareAndSwapPointer(&up, ...

Во время компиляции CAS будет заменять только то, что хранится в up, а не в ptr. Как указал zeebo@#go-nuts, это не желаемый результат.


person ANisus    schedule 14.08.2012    source источник


Ответы (1)


mcef@#go-nuts опубликовал ответ, как конвертировать **T:

(*unsafe.Pointer)(unsafe.Pointer(ptr)), где ptr имеет тип **T.

zeebo@#go-nuts предоставил рабочий пример (размещен здесь с разрешения):

package main

import (
    "fmt"
    "sync/atomic"
    "unsafe"
)

type T struct {
    value int
}

func Swap(dest **T, old, new *T) bool {
    udest := (*unsafe.Pointer)(unsafe.Pointer(dest))
    return atomic.CompareAndSwapPointer(udest,
        unsafe.Pointer(old),
        unsafe.Pointer(new),
    )
}

func main() {
    x := &T{42}
    n := &T{50}
    fmt.Println(*x, *n)

    p := x
    Swap(&x, p, n)
    fmt.Println(*x, *n)
}
person ANisus    schedule 14.08.2012
comment
Как бы вы это сделали, если бы T был интерфейсом, а не struct? - person Francesco Casula; 20.12.2019