Go 语言入门4 – 对象

一、自定义结构

定义结构:type 结构名称 struct

*注:go语言中是没有类这回事,但是它使用了其他方式来充当类,比如一个文件xxx.go那么就属于一个xxx类。go语言对命名方式做了一点智能化处理,如果名字是以小写开头的则只能在包范围内访问,如果是以大写字母开头的,则属于公开,类似于java、php中的public。

1.1、定义结构

type User struct {
   id   int
   name string
}

type Admin struct {
   user User
   role string
}

1.2、赋值

var user User
user.id = 1
user.name = "alan"
fmt.Println(user)

lisa := User{2, "lisa"}
lily := User{id:2,name: "lily"}
fmt.Println(lisa)
fmt.Println(lily)

二、方法

  • 方法的定义方法实际上也是函数,只是在声明时,在关键字 func 和方法名之间增加了一个参数
    • 普通的函数定义 func 方法名(入参) 返回值
    • 自定义类型的方法定义 func (接收者) 方法名 (入参)  返回值
  • 方法的值传递和指针传递
    • func (u user) notify() 拷贝一份 user
    • func (u *user) changeEmail(newEmail string) 传递指针(即地址),内部改变会影响外部
//定义一个类型
type User struct {
   id   int
   name string
}

//定义3个方法
func (u User) getName() string {
   return u.name;
}

func (u *User) setName(name string) {
   u.name = name
}
func (u User) println() {
   fmt.Println(u)
}

//测试方法
func test3() {
   var user User
   user.id = 1
   user.name = "alan"
   fmt.Println(user.getName())// alan
   user.setName("Alan2")
   user.println()// 1 Alan2
}

注意:“再强调一次,println() 操作的是一个副本,只不过这次操作的是从 user 指针指向的值的副本。”

三、嵌入类型

  • Go 语言允许用户扩展或者修改已有类型的行为。这个功能是通过嵌入类型 type embedding 完成的。嵌入类型是将已有的类型直接声明在新的结构类型里。被嵌入的类型被称为新的外部类型的内部类型。
  • Java 通常可以通过继承或组合的方式实现嵌入类型要实现的功能。
  • “要嵌入一个类型,只需要声明这个类型的名字就可以了”,即 user 而不是 u user, u user 是声明字段
  • 内部类型的方法可以被提升到外部类型直接使用

*注:嵌入类型实际上就是go的多态,类似于java的继承。

//定义一个user基础类型
type User struct {
   id   int
   name string
}
//定义个admin基础类型
type Admin struct {
   user User
   role string
}
//定义一个admin2嵌入user类型
type Admin2 struct {
   User
   role string
}

//测试方法
func test4() {
   var admin Admin;//定义一个admin对象
   admin.user = User{id: 1, name: "alan"};
   admin.role = "Administrator"

   admin.setName("test") //错误,这里的admin并不会继承user中的方法

   admin2 := Admin2{role: "Administrator"};
   admin2.id = 1
   admin2.name = "alan"
   admin2.getName()//这里的admin2对象会自动继承user中的方法
   admin2.println()

}
//给User类型添加getName函数
func (u User) getName() string {
   return u.name;
}
//给User类型添加setName函数
func (u *User) setName(name string) {
   u.name = name
}
//给User类型添加println函数
func (u User) println() {
   fmt.Println(u)
}

Go语言入门3 – 容器

容器

  • Array 数组
  • Slice 切片(可以看成动态的数组)
  • Map 映射

一、Array 数组

  • [10]int 和 [20]int 是不同类型,数组类型相同要长度和元素类型完全相同才可以
  • func loopArray(arr2 [3]int) 是值传递,入参会拷贝一份数组,所以如果数组很大,从内存和性能上函数传递数组值都是很大的开销,需要避免(使用指针可以实现”引用传递” func loopArray(arr2 *[3]int),调用方传入 &arr2)
  • 在 Go 中一般不直接使用数组,而是使用切片
  • 数组是定长的,不可扩展,切片相当于动态数组
import "fmt"

func defineArray() [3]int {
   // 定义数组,不赋初值(使用默认值)
   var arr1 [5]int // [0 0 0 0 0]
   // 定义数组,赋初值
   arr2 := [3]int{1, 2, 3} // [1 2 3]
   // 定义数组,由编译器来计算长度,不可写成[],不带长度或者 ... 的表示切片
   arr3 := [...]int{4, 5, 6, 7} // [4 5 6 7]
   // 创建指针数组
   arr4 := [2]*string{new(string), new(string)}
   *arr4[0] = "hello"
   *arr4[1] = "go"
   // 为指定索引位置设置值
   arr5 := [3]int{1:10} // [0,10,0]
   // 二维数组
   var grid [4][5]int // [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
   // 数组拷贝,直接复制一份 arr2 给 arr6
   arr6 := arr2

   fmt.Println(arr1, arr2, arr3, arr4, arr5, arr6, grid)// arr4 打印出来的是地址 [0xc00000e1e0 0xc00000e1f0]
   fmt.Println(*arr4[0]) // hello
   return arr2
}

// 数组是值传递,这里的入参会拷贝一份数组(使用指针可以实现"引用传递")
func loopArray(arr2 [3]int) {
   // 通用方法
   for i := 0; i < len(arr2); i++ {
      fmt.Println(arr2[i])
   }
   // 最简方法,只获取数组下标
   for i := range arr2 {
      fmt.Println(arr2[i])
   }
   // 最简方法,获取数组下标和对应的值
   for i, v := range arr2 {
      fmt.Println(i, v)
   }
   // 最简方法,只获取值,使用 _ 省略变量
   for _, v := range arr2 {
      fmt.Println(v)
   }
}

二、Slice 切片

切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的大小。

切片有 3 个字段分别是指向底层数组的指针、切片访问的元素的个数(即长度)和切片允许增长到的元素个数(即容量)

5842684-3ed9eb450701d434

从切片 slice1 创建出来的切片 slice2,slice1 和 slice2 共享底层数组,一个修改了共享部分的元素,另一个也会感知

2.1、创建切片

// 1、使用make函数创建一个字符串切片,长度和容量都是5
slice1 := make([]string, 5)

// 2、创建一个int切片,长度是3,容量是5
slice2 := make([]int, 3, 5)

// 3、使用字面量创建切片,长度是3,容量是3
slice3 := []int{1, 2, 3} // [3]int{1, 2, 3}

// 4、创建 nil 切片,长度为0,容量为0
var slice4 []int

// 5、创建空切片,长度为0,容量为0
slice5 := make([]int, 0)
slice6 := []int{}

// 6、自定义底层数组,通过该底层数组创建切片
arr := [5]int{1, 2, 3, 4, 5}

// 数组转化为切片,左闭右开 [arr[2]~arr[4])
slice7 := arr[2:4] // [3,4]
slice8 := arr[2:]  // [3,4,5]
slice9 := arr[:4]  // [1,2,3,4]
slice10 := arr[:]   // [1,2,3,4,5]

实际上还有第七种创建切片的方式:根据切片创建切片,称为 reslice

2.2、切片使用

slice1 := []int{1, 2, 3, 4, 5}

// 1、根据索引获取切片元素
fmt.Println(slice1[1]) // 2

// 2、根据索引修改切片元素
slice1[3] = 400
fmt.Println(slice1) // [1, 2, 3, 400, 5]

// 3、根据切片创建切片,和根据自定义数组创建切片方式相同,长度是2=3-1,容量是4=5-1
// 但是需要格外注意,新生成的切片 slice2 和原始切片 slice1 的指针元素指向了相同的底层数组,所以修改元素要注意
slice2 := slice1[1:3] // [2, 3]
slice2[1] = 300
fmt.Println(slice2) // [2, 300]
fmt.Println(slice1) // [1, 2, 300, 400, 5] slice1也发生了变化

// 4、拷贝 slice 中的元素
fmt.Println("copy")
slice3 := []int{0, 0, 0, 0, 0}
slice4 := []int{1, 2, 3}
copy(slice3, slice4)
fmt.Println(slice3) // [1, 2, 3, 0, 0]
fmt.Println(slice4) // [1, 2, 3]    

// 5、删除 slice 中的元素,删除slice5[2]=3
fmt.Println("delete")
slice5 := []int{1, 2, 3, 4}
slice5 = append(slice5[:2], slice5[3:]...)
fmt.Println(slice5) // [1, 2, 4]

2.3、append 增加切片长度

5842684-081821049d9e13f3

// 1、创建原始切片,长度是5,容量是5
slice := []int{10, 20, 30, 40, 50}

// 2、reslice 新切片,长度是2,容量是4
newSlice := slice[1:3] // [20, 30]

// 由于底层数组还有容量,可以直接追加元素而容量不变
newSlice = append(newSlice, 60) // [20, 30 ,60] 长度是3,容量是4
fmt.Println(newSlice)           // [20, 30 ,60]
fmt.Println(slice)              // [10, 20, 30 ,60, 50]

// 长度4,容量4
slice := []int{10, 20, 30, 40}
// 此时切片容量用完了,再追加需要扩容,此处会新加数组,长度为原数组的2倍,即 newSlice 的底层数组是新数组,新切片容量为8;
// 而 slice 的底层数组是旧数组,二者互不影响
newSlice := append(slice, 50)
fmt.Println(slice)    // [10, 20, 30, 40]
fmt.Println(newSlice) // [10, 20, 30, 40, 50]
newSlice[0] = 100
fmt.Println(slice)    // [10, 20, 30, 40]
fmt.Println(newSlice) // [100, 20, 30, 40, 50]

这里是我自己的测试代码:

b := make([]string, 3, 5)
b[0] = "A"
b[1] = "B"
b[2] = "C"
//b[3]="C1"
//b[4]="C2"
b_1 := append(b, "D")
b_1 = append(b, "E")
fmt.Println("b:", b)
fmt.Println("b_1:", b_1)

b1 := []int{1, 2, 3, 4, 5}
var b2 []int
b3 := b1[0:2]
fmt.Println(b1)

b1[0] = 100

fmt.Println(b2)
fmt.Println(b3)
fmt.Println(&b1[0])
fmt.Println(&b3[0])
fmt.Println(len(b3))

fmt.Println("b1:", b1)
b1_1 := append(b1, 6);
b1_2 := append(b1_1, 7);
b1_3 := append(b1_2, 8);
b1_3 = append(b1_3, 9);
b1_3 = append(b1_3, 10);
b1_3 = append(b1_3, 11);
b1_3 = append(b1_3, 12);
b1_3 = append(b1_3, 13);
b1_3 = append(b1_3, 14);
b1_3 = append(b1_3, 15);
b1_3 = append(b1_3, 16);
b1_3 = append(b1_3, 17);
b1_3 = append(b1_3, 18);
b1_3 = append(b1_3, 19);
b1_3 = append(b1_3, 20);
b1_3 = append(b1_3, 21);
//b1_1 = append(b1, 9);
//b1_1 = append(b1, 10);

fmt.Println("b1_1:", b1_1)
fmt.Println("b1_2:", b1_2)
fmt.Println("b1_3:", b1_3)
fmt.Println("b1_3:", len(b1_3))
fmt.Println("b1_3:", cap(b1_3))

5842684-dc4d519b7d344b50

  • 当切片容量(而非数组长度,默认切片容量等于数组长度,也可以显示指定)用完了,再追加需要扩容,此处会新建数组,长度为原数组的2倍,然后将旧数组元素拷贝到新数组,newSlice 的底层数组是新数组,newSlice 容量为8;而 slice 的底层数组是旧数组,二者互不影响。
  • slice 扩容机制:在切片的容量小于 1000 个元素时,总是会成倍地增加容量。一旦元素个数超过 1000,容量的增长因子会设为 1.25,也就是会每次增加 25% 的容量。

2.4、显示设置容量

在没有显示指定容量的情况下,切片容量就是其底层数组的长度,如果在创建切片时设置切片的容量和长度一样,就可以强制让新切片的第一个 append 操作创建新的底层数组,与原有的底层数组分离。新切片与原有的底层数组分离后,可以安全地进行后续修改

source := []string{"Apple", "Orange", "Plum", "Banana", "Grape"}
// 长度为1=3-2,容量为1=3-2  source[i:j:k] 长度=j-i 容量=k-i
slice := source[2:3:3]
fmt.Println(source) // ["Apple", "Orange", "Plum", "Banana", "Grape"]
fmt.Println(slice) // ["Plum"]
// 超出切片容量3,需要新建数组
slice = append(slice, "Kiwi")
fmt.Println(source) // ["Apple", "Orange", "Plum", "Banana", "Grape"]
fmt.Println(slice) // ["Plum", "Kiwi"]

2.5、合并切片

s1 := []int{1, 2}
s2 := []int{3, 4}
fmt.Println(append(s1,s2...)) // [1, 2, 3, 4]

2.6、迭代切片

  slice := []int{10, 20, 30, 40}
    // 与数组迭代一样,可以使用 for range + 普通 for 循环
    for index,value := range slice {
        fmt.Println(index, value)
    }

2.7、函数间传递切片

在函数间传递切片就是要在函数间以值的方式传递切片。由于切片的尺寸很小,在函数间复制和传递切片成本也很低;而在函数间传递数组是需要拷贝整个数组的,所以内存和性能上都不好
调用函数,传递一个切片副本,实际上内部还是传递了对数组的指针,所以 foo 内部的操作会影响 main 中的 slice。

import "fmt"

func foo(slice []int) []int {
   slice[0] = 100
   return slice
}

func main() {
   // 1、创建一个 slice
   slice := []int{1, 2, 3, 4, 5}
   fmt.Println(slice) // [1, 2, 3, 4, 5]
   // 2、调用函数,传递一个切片副本,实际上内部还是传递了对数组的指针,
   // 所以 foo 内部的操作会影响 main 中的 slice
   slice2 := foo(slice)
   fmt.Println(slice2) // [100, 2, 3, 4, 5]
   fmt.Println(slice) // [100, 2, 3, 4, 5]
}

三、Map 映射

  • Map 是一个存储键值对的无序集合,就是说不保证顺序
  • Slice、Map、function 以及包含切片的结构类型不能作为 Map 的 key
  • map在函数间传递,不会拷贝一份map,相当于是”引用传递”,所以remove函数对传入的map的操作是会影响到main函数中的map的

3.1、基本用法

// 1、使用 make 创建 map,key为string,value为int
map1 := make(map[string]int)
// 2、使用字面量创建 map - 最常用的姿势,key为string,value为slice,初始值中的slice可以不加 []string 定义
map2 := map[string][]string{"hi": {"go", "c"}, "hello": []string{"java"}}
// 3、创建空映射
map3 := map[string]string{} // map3 := map[string]string nil映射
fmt.Println(map1, map2, map3)

// 4、向映射添加值
fmt.Println("map put")
map3["a"] = "x"
map3["b"] = "y"
fmt.Println(map3) // map[a:x b:y]

// 5、获取值并判断是否存在
value, exist := map3["c"]
if exist {
fmt.Println(value)
} else {
fmt.Println("map3[\"c\"] does not exist")
}

// 6、迭代
fmt.Println("iterat")
for key, value := range map3 {
fmt.Println(key, value)
}

// 7、从 map 中删除元素
delete(map3, "a")
fmt.Println(map3) // map[b:y]

以下是我的笔记代码:

m1 := make(map[string]string)
m1["a"] = "A"
m1["b"] = "B"
m1["c"] = "C"
m1["d"] = "D"
fmt.Println(m1)

m2 := map[int]int{}
m2[0] = 100
m2[1] = 100 * m2[0]
m2[2] = 100 * m2[0]
fmt.Println(m2)

parserS1(m1);
//delete(m1,"a")
v, m_1 := m1["a"]
if m_1 {
   fmt.Println("存在的", v)
} else {
   fmt.Println("不存在的", m_1)
}

for i, n := range m1 {
   fmt.Printf("me-> Key %s : %s \n", i, n)
}

3.2、函数间传递映射

import "fmt"

// map在函数间传递,不会拷贝一份map,相当于是"引用传递",所以remove函数对传入的map的操作是会影响到main函数中的map的
func remove(map4 map[int]int)  {
   delete(map4, 1)
}

func main() {
   map4 := map[int]int{0:0, 1:1, 2:2}
   fmt.Println(map4) // map[0:0 1:1 2:2]
   remove(map4)
   fmt.Println(map4) // map[0:0 2:2]
}

 

Go语言入门2 – 语法

一、变量定义

四种方式:

  • 完全体:var name type
  • 类型推断:var name = value
  • 最简体:name := value(仅用于函数内变量,包内变量不行)
  • 变量聚合定义:var( name1=value1 name2=value2 )
package main

import "fmt"

// 定义包内变量
var (
   aa = 1
   bb = "lanxin"
)

// 定义变量,只使用默认初值
func variableZeroValue()  {
   var a int       // 0
   var s string    // ""
   var b bool      // false
   fmt.Println(a, s, b)
}

// 定义变量,赋初值
func variableInitialValue()  {
   var a, b int = 1, 2
   b = 3
   var s string = "lanxin"
   fmt.Println(a, b, s)
}

// 类型推断
func variableTypeDeduction()  {
   var a, b, c, d  = 1, 2, true, "hi"
   fmt.Println(a, b, c, d)
}

// 最简定义变量方式
func variableShorter() {
   a, b, c, d := 3, 2, true, "hi"
   fmt.Println(a, b, c, d)
}

func main() {
   variableZeroValue()
   variableInitialValue()
   variableTypeDeduction()
   variableShorter()
   fmt.Println(aa, bb)
}

二、内建变量类型

8 类变量类型:

  • bool
  • string
  • (u)int、(u)int8、(u)int16、(u)int32、(u)int64
  • uintptr 指针
  • byte
  • rune 字符型,32 位,类比 char
  • float32、float64
  • complex32、complex64 复数 i = √-1

注意:类型转换必须强制转,转化成的类型可以不带小括号,如下:

// 强制类型转换
func triangle()  {
   var a, b int = 3, 4
   var c int
   // float64 和 int 可以不加小括号,也可以加上
   // 开方内建函数定义:func Sqrt(x float64) float64
   c = int(math.Sqrt(float64(a*a + b*b)))
   fmt.Println(c)
}

三、常量与枚举

  • 常量定义方式(常量必须有 value)
    • 完全体:const name type = value
    • 后续的使用自动补类型:const name = value
  • 枚举定义方式(Go 没有枚举,用 const 块来定义)
    • 自定义枚举:const ( name1=value1 name2=value2 )
    • iota 表达式枚举:const ( name1=iota表达式 name2 )
// 常量
func consts() {
   // 指定类型
   const filename string = "filename-const"
   // 不指定类型,表示类型不定
   const a, b = 3, 4
   var c int
   // 由于类型不定,所以这里不需要强转,如果定义为 const a, b int = 3, 4,则需要强转
   c = int(math.Sqrt(a*a + b*b))
   fmt.Println(filename, a, b, c)
}

// 枚举
func enums() {
   // 使用 const 块来实现枚举
   const (
      java = 0
      cpp  = 1
      c    = 2
   )
   fmt.Println(java, cpp, c) // 0 1 2
   // 使用 iota 块来实现自增枚举
   const (
      java1 = iota
      cpp1
      c1
   )
   fmt.Println(java1, cpp1, c1) // 0 1 2
}

 

四、条件语句

if:变量可以定义在 if 块内,其作用域就只在 if 块内。

package main

import (
   "fmt"
   "io/ioutil"
)

func readFile() {
   const filename = "abc.txt"
   // Go 函数可以返回两个值
   // func ReadFile(filename string) ([]byte, error)
   contents, err := ioutil.ReadFile(filename)
   if err != nil {
      fmt.Println(err)
   } else {
      // contents 是 []byte, 用%s 可以打印出来
      fmt.Printf("%s", contents)
   }
   // if 语句外部可访问
   fmt.Printf("%s", contents)
}

func readFileShorter() {
   const filename = "abc.txt"
   // Go 函数可以返回两个值
   // func ReadFile(filename string) ([]byte, error)

   if contents, err := ioutil.ReadFile(filename); err != nil {
      fmt.Println(err)
   } else {
      // contents 是 []byte, 用%s 可以打印出来
      fmt.Printf("%s", contents)
   }
   // if 语句外部不可访问
   //fmt.Printf("%s", contents) // 报错
}

从上边可以看出 Go 对文件操作也非常简单。

switch:默认自带break,如果想穿下去执行,使用 fallthrough

// switch 默认自带break,如果想穿下去执行,使用 fallthrough
func eval(a, b int, op string) int {
   var value int
   switch op {
   case "+":
      value = a + b
   case "-":
      value = a - b
   default:
      panic("unsupport operator" + op)
   }
   return value
}

五、循环

for:for 的三个组件都可省略,Go 没有 while,用 for 来替代

package main

import (
   "bufio"
   "fmt"
   "os"
)

func sum() int {
   var value int
   for i := 0; i <= 100; i++ {
      value += i
   }
   return value
}

// 等同于 while(true)
func deadLoop() {
   for {
      fmt.Println("this is a deadLoop")
   }
}

// Go 没有while,循环全部用 for,for的三个组件都可以省略
func printFile(filename string) {
   // 打开文件
   file, err := os.Open(filename)
   // 如果出错,结束进程
   if err != nil {
      panic(err)
   }
   // 获取读取器
   scanner := bufio.NewScanner(file)
   // 读取:It returns false when the scan stops, either by reaching the end of the input or an error
   for scanner.Scan() {
      fmt.Println(scanner.Text())
   }
}

六、函数

func 函数:

  • 可以有多个返回值
  • 函数的参数类型可以是 func – 函数式编程
  • 支持可变长参数
======================== 可以有多个返回值 =========================
// 函数可返回多个值
// 接收:q, r := div(10, 3)
// 如果只用其中一个值,另一个用下划线:q, _ := div(10, 3)
func div(a, b int) (int, int) {
   return a / b, a % b
}
// use
q, _ := div(10, 3)

======================== 函数的参数类型可以是 func =========================
// 可以使用函数作为参数,函数参数与内部参数一样,函数名在前,函数类型在后
// 后续传参,可以使用匿名内部函数,也可以先定义函数再传入
func apply(op func(int, int) int, a,b int) int {
   return op(a, b)
}
// use
result := apply(func(x int, y int) int {
   return x + y
}, 10,4)

======================== 支持可变长参数 =========================
// 可变长参数
func sum2(nums ...int) int {
   s := 0
   for i := range nums {
      s += nums[i]
   }
   return s
}
// use
sum2(1, 2, 3)

七、指针

Go 只有值传递,引用传递需要借助指针实现,引用传递实际上也是值传递,只是传递的是地址

// 值传递,函数参数拷贝了一份外界的 a, b
func swap_by_value(a, b int) {
   b, a = a, b
}
// use
a, b := 3, 4
swap_by_value(a, b)
fmt.Println(*(&a), b) // 3 4 没有实现交换

函数参数拷贝了一份外界的 a, b

// Go 只有值传递,想实现引用传递,使用指针
// *int 代表是指针类型,此时会将外界传入的 &a 拷贝给 这里的a,即这里的 a 拿到的是外界的 a 的地址
// 通过 *a,由于 a 是 &a,这里的 *a 相当于 *(&a) ,即从地址中取值
// 由于函数内部直接操作的是外界的 a,b 的内存地址,所以可以实现引用传递
func swap_by_pointer(a, b *int) {
   *b, *a = *a, *b
}
// use
swap_by_pointer(&a, &b)
fmt.Println(a, b)
*int 代表是指针类型,此时会将外界传入的 &a 拷贝给 这里的a,即这里的 a 拿到的是外界的 a 的地址
通过 *a,由于 a 是 &a,这里的 *a 相当于 *(&a) ,即从地址中取值
由于函数内部直接操作的是外界的 a,b 的内存地址,所以可以实现引用传递

 

Go语言入门1 – 环境搭建

官方文档:https://golang.org/doc/install,被墙了,所以国内打不开,可以在这个网站下载:https://studygolang.com/dl 。本文以 windows 自动安装版为例:

一、下载:https://studygolang.com/dl/golang/go1.12.4.windows-amd64.msi

安装就不需要说了吧。

➜ ~ go version
go version go1.12.4 windows/amd64

 

二、第一个 Go 程序

使用 GoLand 进行开发,IDE下载地址:https://www.jetbrains.com/go/

package main

import (
   "fmt"
)

func init() {
   fmt.Printf("init\n")
}

func main() {
   fmt.Printf("main\n")
}

运行两种方式:

使用 GoLand 直接 debug / run
执行 go build,然后执行生成的可执行文件 ./helloworld 即可

Windows下JetBrains CLion中文输出乱码的解决方法

JetBrains公司推出的 C/C++ IDE CLion,在编写代码时效率非常高,相信以后也会成为开发C/C++项目的首选。

CLion输出中文时,都会产生乱码,不过也有解决办法,示例代码如下:

#include <iostream>

using namespace std;

int main() {
std::cout << “Hello, World!” << std::endl;
cout << “速度嘎是的反垃圾开始都看过是对方感觉啊” << endl;
return 0;
}

输出效果:

C:\Users\Administrator\CLionProjects\untitled\cmake-build-debug\untitled.exe
Hello, World!
閫熷害鍢庢槸鐨勫弽鍨冨溇寮€濮嬮兘鐪嬭繃鏄鏂规劅瑙夊晩

Process finished with exit code 0

解决方法:

File->Setting->Editor->File Encodings

QQ截图20190428152912

 

代码文档要转成GBK,然后就可以了。

 

QQ截图20190428152933

1161718192031
 
Copyright © 2008-2021 lanxinbase.com Rights Reserved. | 粤ICP备14086738号-3 |