Как присвоить строку массиву байтов

Я хочу присвоить строку массиву байтов:

var arr [20]byte
str := "abc"
for k, v := range []byte(str) {
  arr[k] = byte(v)
}

Есть другой метод?


go
person sofire    schedule 07.11.2011    source источник
comment
Если длина str больше, чем длина arr, вы получите ошибку индекса вне допустимого диапазона.   -  person peterSO    schedule 07.11.2011
comment
[]byte(“abc”), чтобы установить строку в байтовый срез. См. stackoverflow.com/a/62740786/12817546 .string(b) или fmt.Sprintf("%s", b), чтобы установить байтовый срез для жала. См. stackoverflow.com/a/62725637/12817546.   -  person Tom L    schedule 09.07.2020


Ответы (9)


Надежно и просто:

[]byte("Here is a string....")
person openwonk    schedule 01.02.2015
comment
Лучшая практика кодирования в Go заключается в использовании фрагмента байтов []byte, а не набора байтов [20]byte при преобразовании строки в байты ... Не верьте мне? Ознакомьтесь с ответом Роба Пайка в этой теме - person openwonk; 14.02.2016
comment
OP спросил о массиве, а не о срезе. В некоторых случаях вам нужно ограничить размер среза и вместо этого использовать массив. Мой ответ ниже обрезает лишние символы, чтобы убедиться, что вы не переполняете массив. - person DavidG; 14.02.2016
comment
Для тех, кто думает, что это выглядит немного странно: это просто преобразование типов в Go: golang.org/ref / spec # Conversions - person Cnly; 17.02.2018
comment
каким-либо способом добавить несколько строк и объединить их? например []byte("one", "two")? - person ; 07.02.2020
comment
К сожалению, нет, @rakim, вы можете передать только одну строку ... поэтому вам нужно сначала объединить их или объединить несколько кусочков байтов (за пределами этого вопроса). - person openwonk; 09.02.2020
comment
И, конечно же, волшебным ингредиентом при переводе абстрактного текста в последовательность байтов является выбранная кодировка текста! Кто-то может задаться вопросом: какая кодировка текста здесь применяется? Отличный вопрос! В данном случае это UTF-8, потому что в Golang строковые литералы всегда содержат текст UTF-8, если они не имеют escape-последовательностей на уровне байтов. - person Dr. Jan-Philip Gehrcke; 20.01.2021

Для преобразования строки в байтовый фрагмент string -> []byte:

[]byte(str)

Для преобразования массива в срез [20]byte -> []byte:

arr[:]

Для копирования строки в массив string -> [20]byte:

copy(arr[:], str)

То же, что и выше, но сначала явно преобразует строку в срез:

copy(arr[:], []byte(str))

  • Встроенная функция copy копирует только в фрагмент, из фрагмента.
  • Массивы - это базовые данные, а срезы - это область просмотра базовых данных.
  • Использование [:] позволяет квалифицировать массив как срез.
  • Строка не квалифицируется как фрагмент, который можно скопировать в, но он квалифицируется как фрагмент, который можно скопировать из (строки неизменяемы).
  • Если строка слишком длинная, copy скопирует только ту часть строки, которая подходит (а многобайтовые руны могут быть скопированы только частично, что приведет к повреждению последней руны в результирующей строке).

Этот код:

var arr [20]byte
copy(arr[:], "abc")
fmt.Printf("array: %v (%T)\n", arr, arr)

... дает следующий результат:

array: [97 98 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] ([20]uint8)

Я также сделал его доступным на Go Playground

person Alexander    schedule 02.09.2016
comment
Вы можете добавить пример преобразования одного символа. Из этого я сделал вывод, что b[i] = []byte("A")[0] работает, но b[i] = 'A' оказывается намного чище. - person Alex Jansen; 05.12.2019
comment
Это не работает для многобайтовых рун: b[1] = '本' - person Alexander; 11.01.2020
comment
один вопрос остается открытым, на который никто не ответил: создает ли []byte(str) новый базовый массив с make() или нет? Или это просто возврат копии указателя на исходную строку. - person Nulik; 18.01.2021

Например,

package main

import "fmt"

func main() {
    s := "abc"
    var a [20]byte
    copy(a[:], s)
    fmt.Println("s:", []byte(s), "a:", a)
}

Выход:

s: [97 98 99] a: [97 98 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
person peterSO    schedule 07.11.2011
comment
Это единственный ответ, который действительно отвечает на исходный вопрос. - person Jack O'Connor; 19.08.2016
comment
Зачем назначать 20 байтов, а не конкретно о том, что вам действительно нужно для строки? Если строке нужно меньше 20, не является ли это неэффективным? А также подвержен ошибкам, если он превышает 20? - person Sir; 20.11.2017
comment
@Sir: Мы не назначаем 20 байтов. Копируем 3 байта, длиной s, функция копирования не тупая. Добавление и копирование фрагментов: количество копируемых элементов составляет минимум len (src) и len (dst). - person peterSO; 20.11.2017

Кусок пирога:

arr := []byte("That's all folks!!")
person Sameh Sharaf    schedule 26.01.2016
comment
Кажется, это не отвечает на вопрос. OP хотел записать байты строки в существующий массив, который может быть длиннее строки. - person Jack O'Connor; 19.08.2016
comment
Использование срезов []byte предпочтительнее массивов [20]byte. Ответ правильный, основанный на передовой практике; если спецификации или код требуют массивов, используйте вместо них copy (см. примеры в другом месте в этом потоке). - person openwonk; 07.04.2017

Думаю, так лучше ..

package main

import "fmt"

func main() {
    str := "abc"
    mySlice := []byte(str)
    fmt.Printf("%v -> '%s'",mySlice,mySlice )
}

Проверьте здесь: http://play.golang.org/p/vpnAWHZZk7

person chespinoza    schedule 11.07.2013
comment
Не лучше. Это не правильно. Он не делает то, о чем задан вопрос. - person peterSO; 12.07.2013

Пойдите, преобразуйте строку в срез байтов

Вам нужен быстрый способ преобразования строки [] в тип байта []. Для использования в таких ситуациях, как сохранение текстовых данных в файле с произвольным доступом или другой тип манипуляции с данными, требующий, чтобы входные данные были байтового типа [].

package main

func main() {

    var s string

    //...

    b := []byte(s)

    //...
}

что полезно при использовании ioutil.WriteFile, который принимает срез байтов в качестве параметра данных:

WriteFile func(filename string, data []byte, perm os.FileMode) error

Другой пример

package main

import (
    "fmt"
    "strings"
)

func main() {

    stringSlice := []string{"hello", "world"}

    stringByte := strings.Join(stringSlice, " ")

    // Byte array value
    fmt.Println([]byte(stringByte))

    // Corresponding string value
    fmt.Println(string([]byte(stringByte)))
}

Выход:

[104 101 108 108 111 32 119 111 114 108 100] привет мир

Проверьте ссылку детская площадка

person ASHWIN RAJEEV    schedule 05.11.2018

Закончил создание для этого методов, специфичных для массива. Очень похоже на пакет encoding / binary с определенными методами для каждого типа int. Например binary.BigEndian.PutUint16([]byte, uint16).

func byte16PutString(s string) [16]byte {
    var a [16]byte
    if len(s) > 16 {
        copy(a[:], s)
    } else {
        copy(a[16-len(s):], s)
    }
    return a
}

var b [16]byte
b = byte16PutString("abc")
fmt.Printf("%v\n", b)

Выход:

[0 0 0 0 0 0 0 0 0 0 0 0 0 97 98 99]

Обратите внимание, что я хотел использовать отступ слева, а не справа.

http://play.golang.org/p/7tNumnJaiN

person DavidG    schedule 13.02.2016
comment
Если вы не голосуете за ответ, оставьте комментарий, почему вы считаете решение неоптимальным или как оно не имеет отношения к вопросу OP. - person DavidG; 18.05.2016
comment
Я думаю, что отрицательные голоса вызваны тем, что byte16PutString - это своего рода повторная реализация встроенной функции copy, которая поддерживает только создание новых массивов вместо использования существующего. copy имеет специальную поддержку компилятора, поэтому он может обрабатывать различные типы аргументов и, вероятно, имеет действительно высокопроизводительную реализацию. Кроме того, вопрос OP задан о записи строки в существующий массив, а не о выделении нового, хотя большинство других ответов, похоже, тоже игнорируют это ... - person Jack O'Connor; 19.08.2016
comment
Спасибо @ JackO'Connor. Я тоже здесь для обучения и ценю конструктивные отзывы, а не просто отрицательные голоса. - person DavidG; 29.08.2016

Помимо методов, упомянутых выше, вы также можете сделать трюк как

s := "hello"
b := *(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s))))

Играйте: http://play.golang.org/p/xASsiSpQmC

Никогда не используйте это :-)

person Brandon Gao    schedule 20.07.2015
comment
Это безумие. Думаю, стоит добавить, но не в конце ответа. Помимо того факта, что он на самом деле не отвечает на вопрос (OP говорит о массиве байтов, а не о срезах), вы, похоже, не получаете правильный объект []byte, используя свое преобразование - он терпит неудачу, когда вы пытаетесь изменить p, см.: play.golang.org/p/WHGl756ucj. В вашем случае не уверен, почему вы предпочитаете двойной небезопасный метод b := []byte(s). - person tomasz; 20.07.2015
comment
@tomasz Я не предпочитаю использовать строку ‹-› [] байт таким образом, просто показываю другой вариант :-) и да, вы правы, я неправильно понял вопрос. - person Brandon Gao; 20.07.2015
comment
Когда я это делаю, результат имеет cap() произвольного размера, что означает чтение в неизвестную память. Чтобы это было правильно, я думаю, вам необходимо выделить полный reflect.SliceHeader размер и вручную установить cap. Примерно так: play.golang.org/p/fBK4dZM-qD - person Lye Fish; 31.12.2016
comment
И я даже не уверен в этом .------------- ^ - Может, так лучше: play.golang.org/p/NJUxb20FTG - person Lye Fish; 31.12.2016
comment
Я согласен, что вам, вероятно, не следует этого делать, но теоретически причина в том, чтобы избежать распределения. [] byte (str) выделяет копию (за исключением некоторых случаев, когда компилятор может оптимизировать и удалить копию) - person Andrew McKinlay; 16.06.2021

Массивы - это значения ... срезы больше похожи на указатели. То есть [n]type несовместимо с []type, поскольку это принципиально две разные вещи. Вы можете получить фрагмент, указывающий на массив, используя arr[:], который возвращает фрагмент, имеющий arr в качестве резервного хранилища.

Один из способов преобразовать фрагмент, например, []byte в [20]byte, состоит в том, чтобы фактически выделить [20]byte, что вы можете сделать, используя var [20]byte (поскольку это значение ... make не требуется), а затем скопировать в него данные:

buf := make([]byte, 10)
var arr [10]byte
copy(arr[:], buf)

По сути, многие другие ответы ошибаются, так это то, что []type НЕ является массивом.

[n]T и []T - это разные вещи!

При использовании отражения []T относится не к типу Array, а к типу Slice, а [n]T - к типу Array.

Вы также не можете использовать map[[]byte]T, но можете использовать map[[n]byte]T.

Иногда это может быть обременительным, потому что многие функции работают, например, с []byte, тогда как некоторые функции возвращают [n]byte (особенно хеш-функции в crypto/*). Например, хеш sha256 - это [32]byte, а не []byte, поэтому, когда новички пытаются записать его, например, в файл:

sum := sha256.Sum256(data)
w.Write(sum)

они получат ошибку. Правильный способ - использовать

w.Write(sum[:])

Однако чего вы хотите? Просто обращаетесь к строке побайтно? Вы можете легко преобразовать string в []byte, используя:

bytes := []byte(str)

но это не массив, это срез. Кроме того, byte! = rune. Если вы хотите работать с «символами», вам нужно использовать _30 _..., а не byte.

person mroman    schedule 13.06.2018