2012-08-26 3 views
0

Можно ли преобразовать указатель в определенное значение в срез?Использовать указатель на значение как срез

Например, я хочу прочитать один байт от io.Reader до uint8 переменной. io.Reader.Read принимает разрез в качестве аргумента, поэтому я не могу просто предоставить ему указатель на мою переменную, как я бы сделал в C.

Я думаю, что создание куска длиной 1, емкость 1 из указателя - безопасная операция. Очевидно, что он должен быть таким же, как создание среза из массива длиной 1, что разрешено. Есть ли простой способ сделать это с помощью простой переменной? Или, может быть, я что-то не понимаю и есть причины, почему это запрещено?

ответ

2

Срез не только указатель, как массив в С. Он также содержит длину и емкость данных, как это:

struct { 
    ptr *uint8 
    len int 
    cap int 
} 

Так что, да, вам нужно будет создать срез , Простейший способ создать кусочек var a uint8 будет []uint8{a}

a := uint8(42) 
fmt.Printf("%#v\n", []uint8{a}) 

(Но перечитав ваш вопрос, это не решение, так как все)

Но если вы хотите, чтобы создать фрагмент из переменной, указывая на то же пространство памяти, вы можете использовать пакет unsafe. Скорее всего, это будет обескуражено.

fmt.Printf("%#v\n", (*[1]uint8)(unsafe.Pointer(&a))[:]) 
+0

Да, я хотел использовать срез, чтобы обеспечить доступ к переменной. Так что это невозможно сделать, не прибегая к небезопасным методам? –

+0

Go не допускает преобразования между uint8 и [1] uint8 (что звучит довольно безопасно для меня). Итак, насколько я знаю, «небезопасный» - единственный способ сделать это. И если я ошибаюсь, мне интересно узнать о лучшем решении. – ANisus

+0

Мой ответ на прямой вопрос: «Возможно ли это ...», и да, это так. Но на самом деле я бы также предложил использовать решение jnml. – ANisus

1

Вместо (более) усложняя эту тривиальную задачу, почему бы не использовать простое решение? То есть Пройдите фрагмент длиной 1, а затем присвойте свой нулевой элемент переменной.

+0

Вот что я сейчас делаю. Я просто хотел узнать, есть ли более красивое решение без определения переменных среза. –

+1

Возможно использовать [1] массив uint8 вместо переменной uint8. Тогда он будет соответствовать io.Reader. – alex

1

Я нашел способ преодолеть свой случай, когда я хочу поставить переменную в io.Reader. Хорошая стандартная библиотека!

import (
    "io" 
    "encoding/binary" 
) 

... 

var x uint8 
binary.Read(reader, LittleEndian, &x) 

В качестве побочного эффекта это работает для любого базового типа и даже для некоторых неосновных.

+0

Приятная находка! Разработчики Go, несомненно, создали для нас очень полезный набор пакетов. – ANisus

+0

Вы понимаете, что (косвенно) используете pass с помощью 'interface {}', утверждения отражения и типа? Является ли это конкуренцией, чтобы найти самый медленный способ, который позволяет избежать примерно двух или более инструкций процессора, которые, вероятно, используются для простого назначения? – zzzz

+0

Да, я понимаю, что здесь используется интерфейс. Я не стремлюсь к производительности прямо сейчас, я искал идиоматическое решение, находя различные вещи на этом пути. Это то, что я нашел, и я просто надеялся, что это может быть полезно кому-то. –

Смежные вопросы