C转GO(基础学习)

Posted 我要出家当道士

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C转GO(基础学习)相关的知识,希望对你有一定的参考价值。

实例(Hello World)

package main
// 为fmt起别名为fmt2
import fmt2 "fmt"
// 调用的时候只需要Println(),而不需要fmt.Println()
import . "fmt"
/*
Go 程序是通过 package 来组织的。
只有 package 名称为 main 的源码文件可以包含 main 函数。
一个可执行程序有且仅有一个 main 包。
通过 import 关键字来导入其他非 main 包。
*/
// 常量定义
const PI = 3.14
func main() {
   fmt.Println("Hello, World!")
}

运行程序

$go run hello.go
Hello, World!

Note

  1. 标识符(包括常量、变量、类型、函数名、结构字段等等)首字母大写,权限为 public;首字母小写为 private。
  2. 使用 go build xxx.go 命令来生成二进制文件
  3. 在 Go 程序中,一行代表一个语句结束。多个语句写在同一行,则必须使用 ; 人为区分。
  4. 支持的注释: // 与 /**/
  5. 字符串可直接使用 + 进行链接,字符串头文件 strings
  6. 声明变量
var isActive bool  // 全局变量声明
var enabled, disabled = true, false  // 忽略类型的声明
const b string = "abc"  //声明常量
func test() {
    var available bool  // 一般声明
    valid := false      // 简短声明
    available = true    // 赋值操作
}
  1. 可使用 ftm.Sprintf 格式化字符串,并赋值给另一个字符串
func main() {
   // %d 表示整型数字,%s 表示字符串
    var stockcode=123
    var enddate="2020-12-31"
    var url="Code=%d&endDate=%s"
    var target_url=fmt.Sprintf(url,stockcode,enddate)
    fmt.Println(target_url)
}
  1. 数据类型
    数值类型初始值都为 0;
    字符串类型(string)初始值为 “”;
    布尔类型(bool)初始值为false。
    如果声明变量值不指名类型,系统也可以自动识别。
  2. 通过 const 关键字来进行常量的定义。
    通过在函数体外部使用 var 关键字来进行全局变量的声明和赋值。
    通过 type 关键字来进行结构(struct)和接口(interface)的声明。
    通过 func 关键字来进行函数的声明。
  3. 局部变量声明了必须要使用。交换可以直接: x,y = y,x
  4. 条件语句
func main() {
   /* 局部变量定义 */
   var a int = 100;
   /* 判断布尔表达式 */
   if a < 20 {
       /* 如果条件为 true 则执行以下语句 */
       fmt.Printf("a 小于 20\\n" );
   } else {
       /* 如果条件为 false 则执行以下语句 */
       fmt.Printf("a 不小于 20\\n" );
   }
   fmt.Printf("a 的值为 : %d\\n", a);
   
   var marks int = 90
   switch marks {
      case 90: grade = "A"
      case 80: grade = "B"
      case 50,60,70 : grade = "C"
      default: grade = "D"  
   }
}
  1. 循环
func main() {
   for i := 1; i <= 9; i++ { // i 控制行,以及计算的最大值
      for j := 1; j <= i; j++ { // j 控制每行的计算个数
         fmt.Printf("%d*%d=%d ", j, i, j*i)
      }
      fmt.Println("")
   }
}
  1. 函数
func function_name( [parameter list] ) [return_types] {
   函数体
}
/*交换*/
func swap(x, y string) (string, string) {
   return y, x
}
func main() {
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)
}
  1. go 中同时包含了函数与方法,函数就是类似C中的函数;方法则与java类似,属于对象的(结构体)。
/* 定义结构体 */
type Circle struct {
  radius float64
}
func main() {
  var c1 Circle
  c1.radius = 10.00
  fmt.Println("圆的面积 = ", c1.getArea())
}
//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
  //c.radius 即为 Circle 类型对象中的属性
  return 3.14 * c.radius * c.radius
}
  1. 闭包函数,即返回值是一个函数,可以直接在调用的地方直接使用函数中的变量。
func getSequence() func() int {
   i:=0
   return func() int {
      i+=1
     return i  
   }
}
func main(){
   /* nextNumber 为一个函数,函数 i 为 0 */
   nextNumber := getSequence()  

   /* 调用 nextNumber 函数,i 变量自增 1 并返回 */
   fmt.Println(nextNumber())  // 1
   fmt.Println(nextNumber())  // 2
   fmt.Println(nextNumber())  // 3
   
   /* 创建新的函数 nextNumber1,并查看结果 */
   nextNumber1 := getSequence()  
   fmt.Println(nextNumber1())  // 1
   fmt.Println(nextNumber1())  // 2
}
  1. nil表示默认零值,很多时候不等于nil意味着出错
  2. 数组
var balance [10] float32
//初始化
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

      初始化数组中 {} 中的元素个数不能大于 [] 中的数字。
      如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:

var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

多维数组
func main() {
    // 创建二维数组
    sites := [2][2]string{}
    // 向二维数组添加元素
    sites[0][0] = "Google"
    sites[0][1] = "Runoob"
    sites[1][0] = "Taobao"
    sites[1][1] = "Weibo"
    // 显示结果
    fmt.Println(sites)
}
/*
    [[Google Runoob] [Taobao Weibo]]
*/

多维数组每行数量可以不一样。 
func main() {
    // 创建空的二维数组
    animals := [][]string{}

    // 创建三一维数组,各数组长度不同
    row1 := []string{"fish", "shark", "eel"}
    row2 := []string{"bird"}
    row3 := []string{"lizard", "salamander"}

    // 使用 append() 函数将一维数组添加到二维数组中
    animals = append(animals, row1)
    animals = append(animals, row2)
    animals = append(animals, row3)

    // 循环输出
    for i := range animals {
        fmt.Printf("Row: %v\\n", i)
        fmt.Println(animals[i])
    }
}
/*
Row: 0
[fish shark eel]
Row: 1
[bird]
Row: 2
[lizard salamander]
*/
  1. go 中指针的用法与 C 一致。
  2. 结构体,使用结构体指针访问成员变量的时候,也是使用 . 符号
type Books struct {
   title string
   author string
   subject string
   book_id int
}
func main() {
    // 创建一个新的结构体
    fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
    // 也可以使用 key => value 格式
    fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
    // 忽略的字段为 0 或 空
   fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
}
  1. 动态数组-切片
//定义切片的时候不需要说明长度
var identifier []type
//使用make进行声明
var slice1 []type = make([]type, len)
//指定容量、capacity为可选参数,最大容量
make([]T, length, capacity)
//常用函数:len(),cap(),append(),copy(),make()。
  1. range用于迭代数组、切片、通道、map
package main
import "fmt"
func main() {
    //这是我们使用range去求一个slice的和。使用数组跟这个很类似
    nums := []int{2, 3, 4}
    sum := 0
    for _, num := range nums {
        sum += num
    }
    fmt.Println("sum:", sum)
    //在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
    for i, num := range nums {
        if num == 3 {
            fmt.Println("index:", i)
        }
    }
    //range也可以用在map的键值对上。
    kvs := map[string]string{"a": "apple", "b": "banana"}
    for k, v := range kvs {
        fmt.Printf("%s -> %s\\n", k, v)
    }
    //range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
    for i, c := range "go" {
        fmt.Println(i, c)
    }
}
  1. map无序键值对,可以像数组那也迭代,使用hash实现的。
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

//常用函数:delete(),
  1. 类型转换,go 不支持隐式转换类型
type_name(expression)
  1. 接口与实现只在使用的时候有关联
/* 定义接口 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* 定义结构体 */
type struct_name struct {
   /* variables */
}

/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
   /* 方法实现*/
}
package main

import (
    "fmt"
)
type Phone interface {
    call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
    fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
}
func (iPhone IPhone) call() {
    fmt.Println("I am iPhone, I can call you!")
}
func main() {
    var phone Phone

    phone = new(NokiaPhone)
    phone.call()

    phone = new(IPhone)
    phone.call()
}
  1. 并发
          通过 go 关键字来开启 goroutine 即可。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。同一个程序中的所有 goroutine 共享同一个地址空间(线程之间通讯效率高)。
//声明
go 函数名( 参数列表 )
//使用
func say(s string) {
        for i := 0; i < 5; i++ {
                time.Sleep(100 * time.Millisecond)
                fmt.Println(s)
        }
}
func main() {
        go say("world")
        say("hello")
}
  1. 通道
          通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
//声明通道,使用关键词chan,需要指明数据类型
ch := make(chan int)
//使用
ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据

//eg
func sum(s []int, c chan int) {
        sum := 0
        for _, v := range s {
                sum += v
        }
        c <- sum // 把 sum 发送到通道 c
}

func main() {
        s := []int{7, 2, 8, -9, 4, 0}

        c := make(chan int)
        go sum(s[:len(s)/2], c)
        go sum(s[len(s)/2:], c)
        x, y := <-c, <-c // 从通道 c 中接收

        fmt.Println(x, y, x+y)
}
  1. 通道缓冲区
ch := make(chan int, 100)

      带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。
      不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。
      如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;
      通道可以使用 range 遍历(通道如果不关闭,range会阻塞)。v, ok := <-ch,如果通道接收不到数据后 ok 就为 false,这时通道就可以使用 close() 函数来关闭。

以上是关于C转GO(基础学习)的主要内容,如果未能解决你的问题,请参考以下文章

go语言学习笔记 — 基础 — 控制流:流程控制

go语言学习笔记 — 基础 — 控制流:goto跳转语句

Go基础--笔记

go基础系列——go 数组转字符串

windows通过Visual Studio Code中配置GO开发环境(转)

[转]Go与C语言的互操作