web Framework
Popularity ranking
https://github.com/speedwheel/awesome-go-web-frameworks/blob/master/README.md#popularity
beego
echo
gin go community document
https://learnku.com/docs/gin-gonic/2019
See cloud gin document
https://www.kancloud.cn/shuangdeyu/gin_book/949418
Quick use of gin
https://www.jianshu.com/p/98965b3ff638
gin-admin-vue
https://www.gin-vue-admin.com/docs/gorm
Official website
Chinese official website
go common library
https://github.com/jobbole/awesome-go-cn
View version number
go version
View env
go env
==Can't pull down the bag==
export GOPATH=/usr/local/go/bin export GOPROXY=https://goproxy.io export PATH=$PATH:$GOPATH export GO111MODULE=on
Open module
go env -w GO111MODULE=on
Set agent
go env -w GOPROXY=https://goproxy.io,direct
Microservice framework
go-kit
go micro
Common web address
Documentation and Technology Forum
go mod usage
Basic data type
String operation
Local gorm struct generation
https://github.com/xxjwxc/gormt.git
Local struct generation
https://github.com/hantmac/fuckdb.git
1 use docker-composer Mode start 2 encounter docker Containers cannot be linked locally mysql When Locally mysql GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES
struct generation
go get -u github.com/gohouse/converter
err := converter.NewTable2Struct(). SavePath("./model.go"). Dsn("root:root@tcp(127.0.0.1:3306)/foroo_beta_shopify?charset=utf8"). TagKey("db"). EnableJsonTag(true). Table("fr_store"). Run() fmt.Println(err) return
Basics
Variables or methods use lowercase, which is equivalent to the initial letter of protect, and uppercase is equivalent to public
Use + to splice strings
Variable declaration var age int;
The data types in constants can only be Boolean, numeric (integer, floating point and complex) and string.
var f string = "Runoob" can be abbreviated as F: = "runoob":
Every statement outside a function must start with a keyword (var, const, func, etc.)
: = cannot be used outside a function.
_ It is mostly used for occupation, indicating that the value is ignored. import _ "./hello"_ The placeholder will only execute init in the import package, and other methods cannot be called
iota is a constant counter of go language, which can only be used in constant expressions
strconv.Itoa(97) converts a number into a string type. string(97)go's own will convert the number into the corresponding ascii code
const ( n1 = iota //0 n2 //1 n3 //2 n4 //3 )
map, slice, chan, pointer and interface are passed by reference by default.
Mutex var lock sync Mutex
var x int64 var wg sync.WaitGroup var lock sync.Mutex func add() { for i := 0; i < 5000; i++ { lock.Lock() // Lock x = x + 1 lock.Unlock() // Unlock } wg.Done() } func main() { wg.Add(2) go add() go add() wg.Wait() fmt.Println(x) }
It should be noted that the read-write mutex lock is very suitable for the scenario of more reading and less writing. If there is little difference between reading and writing operations, the advantages of the read-write lock will not be brought into play.
var ( x int64 wg sync.WaitGroup lock sync.Mutex rwlock sync.RWMutex ) func write() { // lock.Lock() / / add mutex lock rwlock.Lock() // Write lock x = x + 1 time.Sleep(10 * time.Millisecond) // Assume that the read operation takes 10 milliseconds rwlock.Unlock() // Write unlock // lock.Unlock() / / unlock the mutex wg.Done() } func read() { // lock.Lock() / / add mutex lock rwlock.RLock() // Read lock time.Sleep(time.Millisecond) // Suppose the read operation takes 1 millisecond rwlock.RUnlock() // Interpretation lock // lock.Unlock() / / unlock the mutex wg.Done() } func main() { start := time.Now() for i := 0; i < 10; i++ { wg.Add(1) go write() } for i := 0; i < 1000; i++ { wg.Add(1) go read() } wg.Wait() end := time.Now() fmt.Println(end.Sub(start)) }
sync.Once actually contains a mutex and a Boolean value. The mutex ensures the security of Boolean value and data, and the Boolean value is used to record whether the initialization is completed. This design can ensure that the initialization operation is concurrent and safe, and the initialization operation will not be executed many times.
var icons map[string]image.Image var loadIconsOnce sync.Once func loadIcons() { icons = map[string]image.Image{ "left": loadIcon("left.png"), "up": loadIcon("up.png"), "right": loadIcon("right.png"), "down": loadIcon("down.png"), } } // Icon is concurrency safe func Icon(name string) image.Image { loadIconsOnce.Do(loadIcons) return icons[name] }
==goroutine high and send operation map using sync Map to operate==
//sync.Map has built-in operation methods such as Store, Load, LoadOrStore, Delete and Range var m = sync.Map{} func main() { wg := sync.WaitGroup{} for i := 0; i < 20; i++ { wg.Add(1) go func(n int) { key := strconv.Itoa(n) m.Store(key, n) value, _ := m.Load(key) fmt.Printf("k=:%v,v:=%v\n", key, value) wg.Done() }(i) } wg.Wait() }
==The lock operation in the code will be time-consuming and expensive because it involves the context switching in kernel state. For basic data types, we can also use atomic operation to ensure concurrency security, because atomic operation is a method provided by Go language, which can be completed in user state, so its performance is better than locking operation. Atomic operations in Go language are provided by the built-in standard library sync/atomic==
// Atomic operation version addition function func atomicAdd() { atomic.AddInt64(&x, 1) wg.Done() }
make is only used for the initialization of slice, map and channel, and returns the three reference types themselves
The reference address between variables can be changed directly
package main func swap(a, b *int) { var temp int temp = *a *a = *b *b = temp } func main() { var a, b = 1, 2 swap(&a, &b) fmt.Println(a) fmt.Println(b) } //Pointer small case var a int fmt.Println(&a) var p *int p = &a *p = 20 fmt.Println(a)
When assigning parameters, you can directly pass an array or slice without assigning them one by one. Pay special attention to adding "..." after the parameters
package main import ( "fmt" ) func test(s string, n ...int) string { var x int for _, i := range n { x += i } return fmt.Sprintf(s, x) } func main() { s := []int{1, 2, 3} res := test("sum: %d", s...) // slice... Expand slice println(res) }
"_" Identifier used to ignore a return value of a function
The return statement without parameters returns the current value of each return variable. This usage is called "bare" return.
func add(a, b int) (c int) { c = a + b return } func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a + b) / 2 return } func main() { var a, b int = 1, 2 c := add(a, b) sum, avg := calc(a, b) fmt.Println(a, b, c, sum, avg) }
Named return parameters allow defer deferred calls to be read and modified through closures.
defer is first in and last out
package main func add(x, y int) (z int) { defer func() { z += 100 }() z = x + y return } func main() { println(add(1, 2)) }
Define a one-dimensional array
var a [5]int = [5]int{1,2,5,6,7} var a = [...]int{1,2,3,5,6} d := [...]struct { name string age uint8 }{ {"user1", 10}, // Element types can be omitted. {"user2", 20}, // Don't forget the comma on the last line. }
"..." cannot be used to define the second dimension of a two-dimensional array
var b [3][2]int = [3][2]int{{1,2},{3,4},{5,6}} var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
Define slice
overall situation: var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} var slice0 []int = arr[start:end] var slice1 []int = arr[:end] var slice2 []int = arr[start:] var slice3 []int = arr[:] var slice4 = arr[:len(arr)-1] //Remove the last element of the slice Local: arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0} slice5 := arr[start:end] slice6 := arr[:end] slice7 := arr[start:] slice8 := arr[:] slice9 := arr[:len(arr)-1] //Remove the last element of the slice //Create slices with make var slice []type = make([]type, len) slice := make([]type, len) slice := make([]type, len, cap)
Define map
scoreMap := make(map[string]int) scoreMap["Zhang San"] = 90 scoreMap["Xiao Ming"] = 100 // If the key exists, ok is true and V is the corresponding value; There is no zero value with ok as false and V as value type v, ok := scoreMap["Zhang San"] if ok { fmt.Println(v) } else { fmt.Println("No one was found") } //Use the delete() function to delete key value pairs delete(scoreMap, "Xiao Ming")//Delete Xiao Ming: 100 from the map
Array output sorted by subscript
tetcc := make(map[int]string,5) tetcc[1] = "smallsha" tetcc[5] = "smallsha1" tetcc[3] = "smallsha2" sli := []int{} for i := range tetcc { sli = append(sli,i) } sort.Ints(sli) for i := 0; i < len(tetcc); i++ { fmt.Println("content",tetcc[sli[i]]) } fmt.Printf("%#v\n", sli) return
if judgment
if test2 :=19; test2> 20 { fmt.Println("test11212121212") }else if test2 < 20 { fmt.Println("test1111") }
switch usage
test3 := 80 switch test3 { case 80: fmt.Println("1") fallthrough //You can use fallthrough to enforce the following case code. case 90: fmt.Println("2") case 100: fmt.Println("3") default: fmt.Println("default") }
Multiple parameter calls
func test(s string, n ...int) string { var x int for _, i := range n { x += i } return fmt.Sprintf(s, x) } s := []int{1, 2, 3} res := test("sum: %d", s...) // slice... Expand slice println(res)
Closure usage
func a() func() int { i := 0 b := func() int{ i++ fmt.Println(i) return i } return b } ccccc := a() ccccc() ccccc() return
The keyword defer is used to register deferred calls.
These calls are not executed until return. Therefore, it can be used for resource cleaning.
Multiple defer statements are executed in a first in and last out manner
The Convention is: use panic for irreparable errors in key processes and error for others.
func main() { test() } func test() { defer func() { if err := recover(); err != nil { println(err.(string)) // Transform the interface {} into a concrete type. } }() panic("panic error!") }
expression
package main import "fmt" type User struct { id int name string } func (self *User) Test() { fmt.Printf("%p, %v\n", self, self) } func main() { u := User{1, "Tom"} u.Test() mValue := u.Test mValue() // Implicit delivery receiver mExpression := (*User).Test mExpression(&u) // Explicitly pass receiver }
Define error http://www.topgoer.com/%E6%96%B9%E6%B3%95/%E8%87%AA%E5%AE%9A%E4%B9%89error.html
//Return exception package main import ( "errors" "fmt" ) func getCircleArea(radius float32) (area float32, err error) { if radius < 0 { // Build an exception object err = errors.New("Radius cannot be negative") return } area = 3.14 * radius * radius return } func main() { area, err := getCircleArea(-5) if err != nil { fmt.Println(err) } else { fmt.Println(area) } } //System throw anomaly package main import "fmt" func test01() { a := [5]int{0, 1, 2, 3, 4} a[1] = 123 fmt.Println(a) //a[10] = 11 index := 10 a[index] = 10 fmt.Println(a) } func getCircleArea(radius float32) (area float32) { if radius < 0 { // Throw yourself panic("Radius cannot be negative") } return 3.14 * radius * radius } func test02() { getCircleArea(-5) } // func test03() { // Delay execution of anonymous functions // When is the delay? (1) The program ends normally (2) when an exception occurs defer func() { // Recover // Why did the program hang up if err := recover(); err != nil { fmt.Println(err) } }() getCircleArea(-5) fmt.Println("Is there any execution here") } func test04() { test03() fmt.Println("test04") } func main() { test04() } //Custom error package main import ( "fmt" "os" "time" ) type PathError struct { path string op string createTime string message string } func (p *PathError) Error() string { return fmt.Sprintf("path=%s \nop=%s \ncreateTime=%s \nmessage=%s", p.path, p.op, p.createTime, p.message) } func Open(filename string) error { file, err := os.Open(filename) if err != nil { return &PathError{ path: filename, op: "read", message: err.Error(), createTime: fmt.Sprintf("%v", time.Now()), } } defer file.Close() return nil } func main() { err := Open("/Users/5lmh/Desktop/go/src/test.txt") switch v := err.(type) { case *PathError: fmt.Println("get path error,", v) default: } }
interface application
// Empty interface as function parameter func show(a interface{}) { fmt.Printf("type:%T value:%v\n", a, a) } // Empty interface as map value var studentInfo = make(map[string]interface{}) studentInfo["name"] = "Li Bai" studentInfo["age"] = 18 studentInfo["married"] = false fmt.Println(studentInfo)
go schedule sync WaitGroup
var wg sync.WaitGroup func hello(i int) { defer wg.Done() // Registration at the end of goroutine - 1 fmt.Println("Hello Goroutine!", i) } func main() { for i := 0; i < 10; i++ { wg.Add(1) // Start a goroutine and register + 1 go hello(i) } wg.Wait() // Wait for all registered goroutine s to end }
go runtime.Gosched()
//Give up CPU time slice, Reschedule tasks (it probably means that you planned to go out for barbecue on a good weekend, but your mother asked you to go on a blind date. The first is that you are very fast on a blind date, and the meeting will not delay you to continue the barbecue. The second is that you are very slow on a blind date. The meeting is yours and mine, and you delay the barbecue, but if you are greedy, you have to go to barbecue if you delay the barbecue.) package main import ( "fmt" "runtime" ) func main() { go func(s string) { for i := 0; i < 2; i++ { fmt.Println(s) } }("world") // Main coordination process for i := 0; i < 2; i++ { // Cut it and assign the task again runtime.Gosched() fmt.Println("hello") } }
runtime.Goexit()
//Quit the current cooperation process (I was on a blind date while having a barbecue. I suddenly found that the blind date was too ugly to affect the barbecue. I decided to let her go, and then there was no more) package main import ( "fmt" "runtime" ) func main() { go func() { defer fmt.Println("A.defer") func() { defer fmt.Println("B.defer") // End the process runtime.Goexit() defer fmt.Println("C.defer") fmt.Println("B") }() fmt.Println("A") }() for { } }
runtime.GOMAXPROCS
//Go1. After version 5, all CPU logical cores are used by default ///Two tasks have only one logical core. At this time, it is to finish one task and then do another task. Set the number of logical cores to 2. At this time, the two tasks are executed in parallel. The code is as follows. func a() { for i := 1; i < 10; i++ { fmt.Println("A:", i) } } func b() { for i := 1; i < 10; i++ { fmt.Println("B:", i) } } func main() { runtime.GOMAXPROCS(2) go a() go b() time.Sleep(time.Second) }
passageway
1. Sending a value to a closed channel will cause panic.
2. Receiving a closed channel will obtain the value until the channel is empty.
3. Performing a receive operation on a closed channel with no value will get the corresponding type of zero value.
4. Closing a closed channel will cause panic.
5. Chan < - int is a channel that can only be sent, which can be sent but cannot be received;
6 < - Chan int is a channel that can only receive, but can not send.
func counter(out chan<- int) { for i := 0; i < 100; i++ { out <- i } close(out) } func squarer(out chan<- int, in <-chan int) { for i := range in { out <- i * i } close(out) } func printer(in <-chan int) { for i := range in { fmt.Println(i) } } func main() { ch1 := make(chan int) ch2 := make(chan int) go counter(ch1) go squarer(ch2, ch1) printer(ch2) }
Channel use cases
type Job struct { Id int RandNum int } type Result struct { job *Job sum int } func createPool(num int, jobChan chan *Job,resultChan chan *Result) { for i := 0; i < num; i++ { go func(jobChan chan *Job,resultChan chan *Result) { for i2 := range jobChan { r_num := i2.RandNum var sum int for r_num !=0 { tmp := r_num % 10 sum += tmp r_num /= 10 } r := &Result{ job: i2, sum: sum, } resultChan <- r } }(jobChan,resultChan) } } func main() { flag.Parse() jobChan := make(chan *Job, 128) resultChan := make(chan *Result, 128) createPool(64, jobChan, resultChan) // 4. Open a printing process go func(resultChan chan *Result) { // Traversal result pipeline printing for result := range resultChan { fmt.Printf("job id:%v randnum:%v result:%d\n", result.job.Id, result.job.RandNum, result.sum) } }(resultChan) var id int // Create a job in a loop and input it into the pipeline for { id++ // Generate random number r_num := rand.Int() job := &Job{ Id: id, RandNum: r_num, } jobChan <- job } return }
select listening channel
select { case <-chan1: // If chan1 successfully reads the data, the case processing statement is executed case chan2 <- 1: // If the data is successfully written to chan2, the case processing statement is executed default: // If none of the above is successful, enter the default process }
flag usage and OS args
var name string var age int var married bool var delay time.Duration flag.StringVar(&name, "name", "Zhang San", "full name") flag.IntVar(&age, "age", 18, "Age") flag.BoolVar(&married, "married", false, "marriage ") flag.DurationVar(&delay, "d", 0, "Delay interval") Or use name := flag.String("name", "Zhang San", "full name") age := flag.Int("age", 18, "Age") married := flag.Bool("married", false, "marriage ") delay := flag.Duration("d", 0, "time interval") //Parsing command line parameters flag.Parse() fmt.Println(name, age, married, delay) //Return other parameters after command line parameters fmt.Println(flag.Args()) //Returns the number of other parameters after the command line parameters fmt.Println(flag.NArg()) //Returns the number of command line parameters used fmt.Println(flag.NFlag()) //os.args if len(os.Args) > 0 { for index, arg := range os.Args { fmt.Printf("args[%d]=%v\n", index, arg) } }
Log file
logFile, err := os.OpenFile("./smallsha.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { fmt.Println("open log file failed, err:", err) return } log.SetOutput(logFile) //Set log file write log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate) log.SetPrefix("[smallsha]") log.Printf("%s","smallsha") log.Println("test") //log.Panic("test1") //log.Fatalln("test2") logger := log.New(os.Stdout, "<New>", log.Lshortfile|log.Ldate|log.Ltime) logger.Println("This is custom logger Log of records.")
Cyclic operation
arr := [5]int{1,2,4,5,6,8} for i,num :=range arr { fmt.Println(i,num) } //while for loop matching channel var ( ch11 = make(chan int) ch12 = make(chan int) ) go func() { for i := 0; i < 10; i++ { ch11 <- i } close(ch11) }() go func() { for { i, ok := <-ch11 if !ok { break } ch12 <- i * i } close(ch12) }() for i := range ch12 { fmt.Println(i) }
Pointer
const MAX int =3 func main(){ a :=[]int{1,3,5} var ptr [MAX]*int; for i = 0; i < MAX; i++ { ptr[i] = &a[i] /* Assign integer address to pointer array */ } for i = 0; i < MAX; i++ { fmt.Printf("a[%d] = %d\n", i,*ptr[i] ) } }
strconv use
s3, _ := strconv.ParseBool("1") fmt.Printf("%# v\n", pretty.Formatter(s3)) return //int to string s2 := 100 i2 := strconv.Itoa(s2) fmt.Printf("%# v\n", pretty.Formatter(i2)) return //string to int s1 := "100" i1, err := strconv.Atoi(s1) if err != nil { fmt.Println(err) return } fmt.Printf("%# v\n", pretty.Formatter(i1)) return
template can be used to register http
package logic import ( "fmt" "html/template" "net/http" ) func init() { http.HandleFunc("/",sayHello) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println(err) return } } type UserInfo struct { Name string Gender string Age int } func sayHello(w http.ResponseWriter,r *http.Request) { // Generate template object by parsing specified file tmpl, err := template.ParseFiles("./hello.html") if err != nil { fmt.Println("create template failed, err:", err) return } // Render the template with the given data and write the results to w user := UserInfo{ Name: "Withered vine", Gender: "male", Age: 18, } // Render the template with the given data and write the results to w tmpl.Execute(w, user) }
Define structure
package main import "fmt" type Books struct { title string author string subject string book_id int } func main() { var Book1 Books /* Declare Book1 as a Books type */ var Book2 Books /* Declare Book2 as a Books type */ /* book 1 describe */ Book1.title = "Go language" Book1.author = "www.runoob.com" Book1.subject = "Go Language course" Book1.book_id = 6495407 /* book 2 describe */ Book2.title = "Python course" Book2.author = "www.runoob.com" Book2.subject = "Python Language course" Book2.book_id = 6495700 /* Print Book1 information */ printBook(&Book1) /* Print Book2 information */ printBook(&Book2) } func printBook( book *Books ) { fmt.Printf( "Book title : %s\n", book.title) fmt.Printf( "Book author : %s\n", book.author) fmt.Printf( "Book subject : %s\n", book.subject) fmt.Printf( "Book book_id : %d\n", book.book_id) } //Structure new and assignment type Person struct { Username string `json:"username"` Password string `json:"password"` } //Declaration construction method func newPerson(username string, password string) *Person { return &Person{ Username: username, Password: password, } } //Defines how to modify the structure func (p *Person) setUsername(username string) { p.Username = username }
map operation
package main import "fmt" func main() { var countryCapitalMap map[string]string /*Create collection */ countryCapitalMap = make(map[string]string) /* map Insert the key - value pair and the corresponding capital of each country */ countryCapitalMap [ "France" ] = "Paris" countryCapitalMap [ "Italy" ] = "Rome" countryCapitalMap [ "Japan" ] = "Tokyo" countryCapitalMap [ "India " ] = "New Delhi" /*Use the key to output map values */ for country := range countryCapitalMap { fmt.Println(country, "The capital is", countryCapitalMap [country]) } /*Check whether the element exists in the collection */ capital, ok := countryCapitalMap [ "American" ] /*Delete element*/ delete(countryCapitalMap, "France") /*If it is determined to be true, it exists, otherwise it does not exist */ /*fmt.Println(capital) */ /*fmt.Println(ok) */ if (ok) { fmt.Println("American Our capital is", capital) } else { fmt.Println("American The capital of does not exist") } }
Declare variable package main import "fmt" func main() { var a string = "Runoob" fmt.Println(a) var b, c int = 1, 2 fmt.Println(b, c) } Declaration method package main import "fmt" func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("Google", "Runoob") fmt.Println(a, b) } Define array var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0} package main import "fmt" func main() { var n [10]int /* n Is an array with a length of 10 */ var i,j int /* Initializing elements for array n */ for i = 0; i < 10; i++ { n[i] = i + 100 /* Set element to i + 100 */ } /* Output the value of each array element */ for j = 0; j < 10; j++ { fmt.Printf("Element[%d] = %d\n", j, n[j] ) } }
Go language structure
package main import "fmt" type Books struct { title string author string subject string book_id int } func main() { var Book1 Books /* Declare Book1 as a Books type */ var Book2 Books /* Declare Book2 as a Books type */ /* book 1 describe */ Book1.title = "Go language" Book1.author = "www.runoob.com" Book1.subject = "Go Language course" Book1.book_id = 6495407 /* book 2 describe */ Book2.title = "Python course" Book2.author = "www.runoob.com" Book2.subject = "Python Language course" Book2.book_id = 6495700 /* Print Book1 information */ fmt.Printf( "Book 1 title : %s\n", Book1.title) fmt.Printf( "Book 1 author : %s\n", Book1.author) fmt.Printf( "Book 1 subject : %s\n", Book1.subject) fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id) /* Print Book2 information */ fmt.Printf( "Book 2 title : %s\n", Book2.title) fmt.Printf( "Book 2 author : %s\n", Book2.author) fmt.Printf( "Book 2 subject : %s\n", Book2.subject) fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id) } Structure as function parameter func printBook( book Books ) { fmt.Printf( "Book title : %s\n", book.title) fmt.Printf( "Book author : %s\n", book.author) fmt.Printf( "Book subject : %s\n", book.subject) fmt.Printf( "Book book_id : %d\n", book.book_id) }
Declare the difference between functions and methods
#function func main() { sum := add(1, 2) fmt.Println(sum) } func add(a, b int) int { return a + b } #method type person struct { name string } func (p person) String() string{ return "the person name is "+p.name } func main() { p:=person{name:"Zhang San"} fmt.Println(p.String()) } #Variable parameter func main() { print("1","2","3") } func print (a ...interface{}){ for _,v:=range a{ fmt.Print(v) } fmt.Println() }
The modified string needs to be converted to byte or run first
func changeString() { s1 := "hello" // Cast type byteS1 := []byte(s1) byteS1[0] = 'H' fmt.Println(string(byteS1)) s2 := "Blog" runeS2 := []rune(s2) runeS2[0] = 'dog' fmt.Println(string(runeS2)) }