Як призначити рядок до масиву байтів


375

Я хочу призначити рядок байтовому масиву:

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

Є інший метод?


11
Якщо довжина strбільше, ніж довжина, arrто ви отримаєте помилку "індекс поза діапазоном".
peterSO

Відповіді:


543

Безпечний і простий:

[]byte("Here is a string....")

14
Найкращі методи кодування в Go - це використання фрагмента байтів, []byteа не набору байтів [20]byteпри перетворенні рядка в байти ... Не вірите мені? Перевірте відповідь Роб Пайк на цю тему
openwonk

9
ОП запитав про масив, а не про фрагмент. У деяких випадках потрібно обмежити розмір фрагмента і використовувати замість цього масив. Моя відповідь нижче обрізає зайві символи, щоб переконатися, що ви не переповнюєте масив.
DavidG

3
Для тих, хто вважає, що це виглядає дещо дивним: це просто перетворення тексту
Cnly

будь-яким способом додати кілька рядків і об'єднати їх? наприклад []byte("one", "two")?
rakim

На жаль, ні, @rakim, ви можете пропустити лише один рядок ... тож, вам потрібно спочатку їх об'єднати або об'єднати декілька фрагментів байтів (за межами цього питання).
openwonk

149

Для перетворення з рядка в байтовий фрагмент 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


Ви можете додати приклад для перетворення одного символу. Я зробив висновок з цього, що b[i] = []byte("A")[0]працює, але в b[i] = 'A'кінцевому підсумку набагато чистіший.
Алекс Янсен

1
Це не працює для багатобайтових рун:b[1] = '本'
Олександр

110

Наприклад,

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]

3
Це єдина відповідь, яка насправді стосується початкового питання.
Джек О'Коннор

Навіщо призначати 20 байтів, а не конкретно про те, що вам насправді потрібно для рядка? Якщо рядку потрібно менше 20, це не біт неефективний? А також схильність до помилок, якщо вона перевищує 20?
Сер

1
@Sir: Ми не призначимо 20 байт. Ми копіюємо 3 байти, довжина - sФункція `копіювання не є німою. Додавання та копіювання фрагментів : "Кількість скопійованих елементів - мінімум len (src) та len (dst)."
peterSO

42

Шматок пирога:

arr := []byte("That's all folks!!")

8
Схоже, це не відповідає на питання. OP хотів записати байти рядка в існуючий масив, який може бути довше, ніж рядок.
Джек О'Коннор

2
Використання зрізів []byteє кращим над масивами [20]byte. Відповідь правильна на основі передового досвіду; якщо специфікація або код потребує масивів, використовуйте copyзамість цього (див. приклади в іншому потоці).
openwonk

25

Я думаю, що це краще ..

package main

import "fmt"

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

Перевірте тут: http://play.golang.org/p/vpnAWHZZk7


3
Це не краще. Це неправильно. Це не робить те, про що задавали питання.
peterSO

10

Перейдіть, перетворіть рядок у байтовий фрагмент

Вам потрібен швидкий спосіб перетворити рядок [] в байт []. Використовувати в таких ситуаціях, як збереження текстових даних у файл випадкового доступу або інший тип маніпуляцій з даними, що вимагає введення даних у байтовому форматі [].

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] привіт, світ

Перевірте посилання на ігровий майданчик


0

Закінчилося створення специфічних методів для цього масиву. Так само, як кодування / бінарний пакет із конкретними методами для кожного типу 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


3
Якщо ви не голосуєте, відповідь залиште коментар, чому ви вважаєте, що рішення не є оптимальним або як воно не відповідає питанню ОП.
DavidG

3
Я думаю, що голосування є тим, що byte16PutStringце свого роду повторне реалізація вбудованої copyфункції, яка підтримує лише створення нових масивів замість використання існуючих. copyмає спеціальну підтримку компілятора, тому він може обробляти різні типи аргументів, і він, ймовірно, має дійсно високопродуктивну реалізацію під обкладинками. Також питання ОП запитували про написання рядка до наявного масиву, а не про виділення нового, хоча більшість інших відповідей, здається, теж ігнорують це ...
Джек О'Коннор,

Дякую @ JackO'Connor Я теж тут для навчання і ціную конструктивні відгуки, а не лише просту думку.
DavidG

не знаю, як це його голос answer- це правильно, кожне тіло тут, щоб навчатись та заохочувати інших
muthukumar helius

-1

Окрім згаданих вище методів, ви також можете зробити трюк як

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

Перейти: http://play.golang.org/p/xASsiSpQmC

Ніколи не слід використовувати це :-)


1
Це божевілля. Я думаю, що варто додати "але не варто" наприкінці своєї відповіді. Крім того, що він насправді не відповідає на питання (OP говорить про байтовий масив, а не фрагменти), ви, здається, не отримаєте належного []byteоб'єкта за допомогою "конверсії" - це погано виходить з ладу при спробі внесення змін p, див. play.golang.org/p/WHGl756ucj . У вашому випадку не впевнені, чому ви віддасте перевагу подвійним небезпечним b := []byte(s)способом.
tomasz

1
@tomasz Я не вважаю за краще робити рядок <-> [] байтом таким чином, просто показуючи інший варіант :-) і так, ви праві, я неправильно зрозумів питання.
Брендон Гао

Коли я це роблю, результат має cap()довільний розмір, це означає, що він читає в невідому пам'ять. Щоб це було правильно, я думаю, вам потрібно буде переконатися, що ви виділите повний reflect.SliceHeaderрозмір і встановите вручну cap. Приблизно так: play.golang.org/p/fBK4dZM-qD
Lye Fish

І я навіть не впевнений у цьому .------------- ^ - Можливо, це краще: play.golang.org/p/NJUxb20FTG
Lye Fish

-1

Масиви - це значення ... фрагменти більше нагадують покажчики. Це є[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. Якщо ви хочете оперувати "символами", вам потрібно скористатися rune... ні byte.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.