go语言的基本语法

几个基本点

  1. 可以不用分号,如果多行写在一行,则必须有分号
  2. 注释两种类型,同java
//必须为main,否则不能作为运行项
package main

import "fmt"

//虽不报错,以下二者是否可以放在方法之外?
var test = "adfsdf"
test2:= "sdfsdf"
//方法必须为main()
func main(){
    // 这也是一种自动推断
    var whatISay = "I Want to say!"
    whatISay2 := "I Want to Say!"
    fmt.Println("Hello world!" + "Haha" + whatISay + whatISay2)
}

基本的数据类型

  1. 数字类型
    int float32 float64 int8 int16 int32 int64 uint8 uint16 uint32 uint64 complex64 complex128 byte(uint8) rune uint(int32) int uintptr(存入指针的无符号)
  2. 布尔型
    true false
  3. 字符串类型
    可以看成字符序列, UTF-8
  4. 派生类型
    (a) 指针类型(Pointer)
    (b) 数组类型
    © 结构化类型(struct)
    (d) Channel 类型
    (e) 函数类型
    (f) 切片类型
    (g) 接口类型(interface)
    (h) Map 类型

变量的零值:
数值类型是0
布尔是false
字符是""

类型推导的前题:
使用了没有类型的var变量 或 :=

package main

import "fmt"
import "reflect"

//基本的变量声明 (原则:如果带了var就带上类型,否则直接用:=)
var length12 int = 3
const length23 int = 5
var boolVar bool = true
var floatVar float64 = 3.335
var uintVar uint = 999
// 一定得都写上,否则会报错,此处不像java一样
var length1, length2 = 3, 2
// 声明时,必须带着var,同类型的话,可以只写最后一个,同mehod参数
var b, c int
const (
    day1 = 1
    day2 = 2
)

const (
    a = iota   //0
    b          //1
    c          //2
    d = "ha"   //独立值,iota += 1
    e          //"ha"   iota += 1
    f = 100    //iota +=1
    g          //100  iota +=1
    h = iota   //7,恢复计数
    i          //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)

// 以下是类型强转的方式
var a interface{} = f
c := a.(int)
fmt.Println(reflect.TypeOf(c)) // int

//如果多了,就 repl.go:39:28: array index 2 out of bounds [0:2]
array1 := [2]string{"zcy", "yyy"}
array2 := [...]string{"zcy"}
//repl.go:40:17: first argument to append must be slice; have <[2]string>
//array1 = append(array1, "kkk")
fmt.Println(array1, array2)
var slice1 []string = []string{"zcy", "yyy"}
//以此来扩大长度,使其靠近cap
slice1 := append(slice1, "xixi")

fmt.Println(slice1)

//声明的时候,不要少了map关键字
map1 := make(map[string]int, 3)
map1["sdfsdf"] = 1
fmt.Println(map1)
0 1 2 ha ha 100 100 7 8
int
[zcy yyy] [zcy]
[zcy yyy xixi]
map[sdfsdf:1]





14 <nil>

重点关注一下指针运算符

var a int = 4
var b int32
var c float32
var ptr *int

/* 运算符实例 */
fmt.Printf("第 1 行 - a 变量类型为 = %T\n", a )
fmt.Printf("第 2 行 - b 变量类型为 = %T\n", b )
fmt.Printf("第 3 行 - c 变量类型为 = %T\n", c )

/*  & 和 * 运算符实例 */
ptr = &a     /* 'ptr' 包含了 'a' 变量的地址 */
fmt.Printf("a 的值为  %d\n", a)
fmt.Printf("*ptr 为 %d\n", *ptr)


i, j := 42, 2701
p := &i         // point to i
fmt.Println(*p) // read i through the pointer
fmt.Println(p)  // 这个肯定是其地址值了,可以终极判断是不是一个对象
*p = 21         // set i through the pointer
fmt.Println(i)  // see the new value of i

var a = "abc"
var b = "abc"
//a的地址:824634121680, b的地址:824634121696
fmt.Printf("a的地址:%d, b的地址:%d \n", &a, &b)
//true ?
fmt.Println(a == b)


第 1 行 - a 变量类型为 = int
第 2 行 - b 变量类型为 = int32
第 3 行 - c 变量类型为 = float32
a 的值为  4
*ptr 为 4
42
0xc000698058
21
a的地址:824640676608, b的地址:824640676992 
true





5 <nil>

函数的声明与使用

import "strconv"
import "fmt"
//返回两个值的时候,要将返回的东西弄成一个元组,即加括号 
//当两个或多个连续的函数命名参数是同一类型,则除了最后一个类型之外,其他都可以省略。
func  methodName1(arg1 int, arg2 string, arg3, arg4 int) (string, error) {
    fmt.Println(arg3, arg4)
    //注意一下int转string的方法
    result := (strconv.Itoa(arg1) + arg2)
    return result, nil
}
result1, err := methodName1(1, "name", 3, 4)
if(err != nil) {
    fmt.Println("error happened")
}

// 此种方法来替代java中的lambda表达式
var  methodName2 = func(arg1 int) bool {return arg1 > 2}
fmt.Println(methodName2(3)) // true

// 命名返回值,此种尽量不用,但要理解
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}


3 4
true

流程控制语句

  1. 很少用(),没用必要,而且这样可以在if时进行初始化等
  2. 没有while语句,for和switch和if三驾马车
import "fmt"

//不用有(),但要有{},同一行是分号
for i:=0; i<4; i++ {
    fmt.Println(i)
}
// <span class="burk">在go中是没有while语句的,统统用for</span>
i = 3
for i<10 {
    i++
    fmt.Println(i)
}
// 这里等同于 while(true){}
//for{}
// 不能用()和for一样
if c:=9; c>3 {
    fmt.Println(c)
}

switch os := "windows"; os{
    case "windows":
        fmt.Println("1====windows")
        //不加这个类似于java,所以其与java是相反的,java的break
        fallthrough 
    case "linux":
        fmt.Println("2----linux")
    default:
        fmt.Println("default")
}
// 表达if elseif else 的语句,switch后面都没有跟着c
switch {
    case c<4:
        fmt.Println("==1")
    case c<3:
        fmt.Println("===2")
    default:
        fmt.Println("====3")
}

//interface{} 这个是go中的Object类
var t interface{} = 1
//获取对象的类型的方法,t.(type)仅在switch中可用 
switch t := t.(type) {
    default:
        fmt.Printf("unexpected type %T", t) // %T prints whatever type t has
    case bool:
        fmt.Printf("boolean %t\n", t) // t has type bool
    case int:
        fmt.Printf("integer %d\n", t) // t has type int
    case *bool:
        fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
    case *int:
        fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}
0
1
2
3
4
5
6
7
8
9
10
9
1====windows
2----linux
==1
integer 1

defer函数的处理

// defer主要是用于资源回收
func method1(arg1 int) int {
    // defer是关键字,不是方法,否则怎么传递参数啊
    defer method2(arg1)
    // 这个先执行,后进先出,是栈的结构
    defer method2(arg1 + 1)
    return arg1
}

func method2(arg1 int){
    import "fmt"
    fmt.Println(arg1)
}

method1(2)  // 3  2
3
2





2

结构体和专属方法

import "fmt"
import "strconv"

type Member struct {
    // 属性后面不带,号
    Name string
    age int
    Children [2]string
    nothing int
}
//如果想改变值,就用指针,直接用对象而不加&的时候,编译器会自动转换
func (member *Member) sayHi(){
    fmt.Println("member's age is "+ strconv.Itoa(member.age))
    fmt.Printf("address is %d \n", &member)
}
// 要么全初始化,要么用名称初始化
m1 := Member{Name: "zcy"}
//too few values in struct initializer: <main.Member> has 4 fields, found 3 initializers
//m2 := Member{"zcy", 23, [2]string{"xixi", "xiaolu"}}
m2 := Member{"zcy", 23, [2]string{"xixi", "xiaolu"}, 2}


m1.sayHi()
fmt.Printf("======================================m1 address is %d \n", (&m1))
(&m1).sayHi()


// 这个可以访问,可以啊,在一个包里,为何不可
m1.age = 23
// 这个方式是错误的
//m1.Children = ['xixi', 'xiaolu']
m1.Children = [2]string{"xixi", "xiaolu"}
//incompatible types in assignment: <[2]string> = <[]string>
//m1.Children = []string{"xixi", "xiaolu"}
fmt.Println(m1, m2)

//如果是这种,即使用值调用也会转为地址调用
func (member *Member) change1(){
    member.age = 1
}
//如果是这种声明,即使用地址调用也是会自动转成值复制
func (member Member) change2(){
    member.age = 2
}

m_change_1 := Member{}
m_change_2 := Member{}
// 0 1 1
fmt.Printf("age is : %d \n", m_change_1.age)
m_change_1.change1()
fmt.Printf("age is : %d \n", m_change_1.age)
m_change_1.age = 0
(&m_change_1).change1()
fmt.Printf("age is : %d \n", m_change_1.age)
// 0 0 0 
fmt.Printf("age is : %d \n", m_change_2.age)
m_change_2.change2()
fmt.Printf("age is : %d \n", m_change_2.age)
m_change_2.age = 0
(&m_change_2).change2()
fmt.Printf("age is : %d \n", m_change_2.age)


member's age is 0
address is 824633745616 
======================================m1 address is &{%!d(string=zcy) 0 [%!d(string=) %!d(string=)] 0} 
member's age is 0
address is 824633745624 
{zcy 23 [xixi xiaolu] 0} {zcy 23 [xixi xiaolu] 2}
age is : 0 
age is : 1 
age is : 1 
age is : 0 
age is : 0 
age is : 0 





12 <nil>

常用的语法

import "fmt"

var array1 []string = []string{"string0", "string1", "string2", "string3", "string4", "string5", "string6"}
// cannot assign <[]string> to <[2]string> in variable declaration: array2 <[2]string>,写2就是数组,不写是切片
//var array2 [2]string = []string{"string1", "string2"}

// ===================切片的操作===================
fmt.Println(array1[1:3], array1[1:], array1[:3], len(array1[:3]))
slice1 := array1[3:]
for i:=0; i<len(slice1); i++ {
    fmt.Println(slice1[i])
}
//有容量有什么用,赋值超了len就报错????
b := make([]int, 2, 5) // len(b)=2, cap(b)=5
b[0] = 2
fmt.Println(b[1]) // 0

map1 := make(map[string] int)
map1["a"] = 5
// 容量是6
map2 := make(map[string] int, 6)
// 每个元素都要有逗号,否则 missing ',' before newline in composite literal
map3 := map[string] int {
    "a" : 4, 
    "b" : 5,
}

//现在知道cap的作用了吧,1000这前翻倍,之后加25%
array1 := make([]int, 2, 3)
array1[0] = 1
array1[1] = 2
array1 = append(array1, 3)
array1 = append(array1, 4)
fmt.Printf("len is %d, cap is %d \n", len(array1), cap(array1))
fmt.Println(array1)

// 容量与长度的关系
map4 := make(map[string]int, 2)
map4["1"] = 1
map4["2"] = 1
map4["3"] = 1
map4["4"] = 1
map4["5"] = 1
fmt.Printf("len is %d, cap is nil, map没有容量一说", len(map4))
[string1 string2] [string1 string2 string3 string4 string5 string6] [string0 string1 string2] 3
string3
string4
string5
string6
0
len is 4, cap is 6 
[1 2 3 4]
len is 5, cap is nil, map没有容量一说




43 <nil>

可以看到声明的方式 []string 和 map[string]int 和 [2]string

协程和通道

import "fmt"
import "sync"
import "time"

chan1 := make(chan int, 3)
wg := sync.WaitGroup{}
wg.Add(2)

type member struct {
    name string
    age int
}

chan2 := make(chan member)

func method1(){
    fmt.Println("I'm in the go routine now!")
    defer wg.Done()
    // 此处在没有值来的时候,是阻塞的
    receive := <-chan1
    fmt.Printf("int receive: %d\n", receive)
    // 此处在没有值来的时候,是阻塞的
    member_var := <-chan2
    fmt.Printf("name: %s, age: %d\n", member_var.name, member_var.age)
}

func method2(){
    defer wg.Done()
    // 箭头的方向是一样
    chan1 <- 7
    time.Sleep(time.Second * 10)
    chan2 <- member{"zcy", 36}
}

go method1()
time.Sleep(time.Second * 10)
go method2()
wg.Wait()
fmt.Println("\nI'm done!")
I'm in the go routine now!
int receive: 7
name: zcy, age: 36

I'm done!





11 <nil>
import "fmt"
import "sync"
import "time"

wg := sync.WaitGroup{}
wg.Add(2)

type member struct {
    name string
    age int
}

chan2 := make(chan member, 2)

func method1(){
    fmt.Println("I'm in the go routine now!--method1")
    defer wg.Done()
    // 此处在没有值来的时候,是阻塞的
    member_var := <-chan2
    fmt.Printf("name: %s, age: %d\n", member_var.name, member_var.age)
    fmt.Println("I'm leaving the go routine now!--method1")
}

func method2(){
    fmt.Println("I'm in the go routine now!--method2")
    defer wg.Done()
    // 箭头的方向是一样
    // 如果不是缓冲通道,此处也是阻塞的
    chan2 <- member{"zcy", 1}
    fmt.Println("chan2 <- member{zcy, 1}")
    chan2 <- member{"zcy", 2}
     fmt.Println("chan2 <- member{zcy, 2}")
    // 取决于缓冲区大小,超了,此处也是阻塞的
    chan2 <- member{"zcy", 3}
    fmt.Println("chan2 <- member{zcy, 3}")
    fmt.Println("I'm leaving the go routine now!--method2")
}
go method2()
time.Sleep(time.Second * 10)
go method1()
wg.Wait()
fmt.Println("\nI'm done!")
I'm in the go routine now!--method2
chan2 <- member{zcy, 1}
chan2 <- member{zcy, 2}
I'm in the go routine now!--method1
name: zcy, age: 1
I'm leaving the go routine now!--method1
chan2 <- member{zcy, 3}
I'm leaving the go routine now!--method2

I'm done!





11 <nil>
import "fmt"
import "sync"
import "time"

wg := sync.WaitGroup{}
wg.Add(2)

type member struct {
    name string
    age int
}

chan2 := make(chan member, 2)

func method1(){
    fmt.Println("I'm in the go routine now!--method1")
    defer wg.Done()
    //chan2在Close后,即会退出这个循环
    for member_var := range chan2 {
        //member_var := <-chan2
        fmt.Printf("name: %s, age: %d\n", member_var.name, member_var.age)
    }
    fmt.Println("即使关了,我们还是可以取出零值来", <-chan2)
    //true
    fmt.Println("是不是等于空值:", member{} == <-chan2)
    fmt.Println("I'm leaving the go routine now!--method1")
}

func method2(){
    fmt.Println("I'm in the go routine now!--method2")
    defer wg.Done()
    // 箭头的方向是一样
    // 如果不是缓冲通道,此处也是阻塞的
    chan2 <- member{"zcy", 1}
    fmt.Println("chan2 <- member{zcy, 1}")
    chan2 <- member{"zcy", 2}
    fmt.Println("chan2 <- member{zcy, 2}")
    // 取决于缓冲区大小,超了,此处也是阻塞的
    chan2 <- member{"zcy", 3}
    time.Sleep(time.Second * 10)
    chan2.Close()
    fmt.Println("chan2 <- member{zcy, 3}")
    fmt.Println("I'm leaving the go routine now!--method2")
}
go method2()
time.Sleep(time.Second * 10)
go method1()
wg.Wait()
fmt.Println("\nI'm done!")
I'm in the go routine now!--method2
chan2 <- member{zcy, 1}
chan2 <- member{zcy, 2}
I'm in the go routine now!--method1
name: zcy, age: 1
name: zcy, age: 2
name: zcy, age: 3
chan2 <- member{zcy, 3}
I'm leaving the go routine now!--method2
即使关了,我们还是可以取出零值来 { 0}
是不是等于空值: true
I'm leaving the go routine now!--method1

I'm done!





11 <nil>
import "fmt"
import "sync"
import "time"

//声明一个lock的语句
var wg sync.WaitGroup = sync.WaitGroup{}
wg.Add(4)
var lock sync.Mutex  

func method1(flag int){
    lock.Lock()
    defer lock.Unlock()
    defer wg.Done()
    time.Sleep(time.Second * 5)
    fmt.Printf("flag %d is int the lock area!\n", flag)
}

go method1(1)
fmt.Println("===================1")
go method1(2)
fmt.Println("===================2")
go method1(3)
fmt.Println("===================3")
go method1(4)
fmt.Println("===================4")
wg.Wait()
===================1
===================2
===================3
===================4
flag 1 is int the lock area!flag 4 is int the lock area!flag 2 is int the lock area!flag 3 is int the lock area!

make和new的区别

  1. new返回的是一个指针,参数是类型,分配的内存会置0,其实其不常用,不如直接声明来的方便
  2. make仅是为slice, map, channel服务的,除此之外无用
  3. 二者作用都是来分配内存,且内存都分配在堆上

虽然无关,总结留此:

  1. 传入参数,返回值等都是按照 “非指针,建对象” 的原则来进行的
  2. 对一些基本类型,一般不用指针,即使是string,人家在go里可是基本类型
  3. 引用类型不是没有的,map slice chan func这四个家伙是引用类型
import "fmt"

type member struct {
    name string
    age int
    children []*member
}

m1 := new(member)
m1.name = "zcy1"
m1.age = 36

m2 := new(member)
m2.name = "xixi"
m2.age = 5

m3 := &member{
    name: "xiaolu", 
    age: -1,
}
//??????????????????????????????????
//reflect.Value.Convert: value of type []*struct { ?name string; ?age int; ?children []*struct 
//{ ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children 
//[]*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; 
//?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct 
//{ ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; 
//?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int } } } } } } } } } } } } } } } cannot be converted to type []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int; ?children []*struct { ?name string; ?age int } } } } } } } } } } } } } }
//m1.children = make([]*member, 2, 2)
//m1.children[0] = m2
//m1.children[1] = m3
// m1 = &member {
//     name: "zcy1",
//     age: 36,
//     children: []*member{m2, m3},
// }

func update(m member) bool{
    m.name = "zcy1"
    m.name = "dad zcy1"
    return true
}
//repl.go:31:8: cannot use <*main.member> as <main.member> in argument to update
//update(m1)
//fmt.Println("after update, ", m1)

func update2(m *member) *member {
    m.name = "zcy1"
    m.name = "dad zcy1"
    fmt.Printf("m内存位置是%p \n", m)
    return m
}
// 可见,通过传入指针类型,可以进行参数修改
fmt.Printf("m1内存的位置%p \n", m1)
m1 = update2(m1)
fmt.Printf("m1内存的位置%p \n", m1)
fmt.Println("after update2, ", m1)

//虽然string是会建新值,但是其仍然是基本类型,所以可以不用指针
func update3(m *member) (member, string) {
    m.name = "zcy2"
    m.name = "dad zcy3"
    str := "dddd"
    //str location 0xc000990ca0 
    //update3 str内存的位置0xc000990ce0 
    fmt.Printf("str location %p \n", &str)
    return *m, str
}
// 可见,如果返回值型,那么会直接返回新的一个对象
//update3  m1内存的位置0xc0007e2480 
//update3  m1内存的位置0xc0007e2900 
fmt.Printf("update3  m1内存的位置%p \n", m1)
m4, str := update3(m1)
fmt.Printf("update3 str内存的位置%p \n", &str)
fmt.Printf("update3  m1内存的位置%p \n", &m4)
m1内存的位置0xc00099a9c0 
m内存位置是0xc00099a9c0 
m1内存的位置0xc00099a9c0 
after update2,  &{dad zcy1 36 []}
update3  m1内存的位置0xc00099a9c0 
str location 0xc000990ca0 
update3 str内存的位置0xc000990ce0 
update3  m1内存的位置0xc00099af00 





40 <nil>

引用类型有哪些:

  1. array不是,任何对它的传递都是复制后的值传递
  2. slice是,存储结构是 loc + len + cap
  3. map是, 存储结构是哈希桶
  4. func是
  5. chan是, 有缓冲区的更是
import "fmt"

type member struct {
    name string
    age int
}
array1 := [...]member{member{"zcy", 12}, member{
    name: "zcy2",
    age: 23,
}}

fmt.Println(array1, &array1)
fmt.Printf("1   location is %p \n", &array1)
fmt.Printf("1.1 location is %p \n", &(array1[0]))
fmt.Printf("1.2 location is %p \n", &(array1[1]))
func test1(m [2]member){
    fmt.Printf("2   location is %p \n", &m)
    fmt.Printf("2.1 location is %p \n", &(m[0]))
    fmt.Printf("2.2 location is %p \n", &(m[1]))
}
// 果然是整体复制了一圈,所以用array的时候要小心一些
test1(array1)

//可以明显看到slice传递的时候,不会进行复制,仅复制了引用的存储结构
slice1 := []member{member{"zcy1", 2}, member{"zcy2", 32}}
fmt.Println(slice1, &slice1)
fmt.Printf("1   location is %p \n", &slice1)
fmt.Printf("1.1 location is %p \n", &(slice1[0]))
fmt.Printf("1.2 location is %p \n", &(slice1[1]))
func test2(m []member){
    fmt.Printf("2   location is %p \n", &m)
    fmt.Printf("2.1 location is %p \n", &(m[0]))
    fmt.Printf("2.2 location is %p \n", &(m[1]))
}
test2(slice1)
[{zcy 12} {zcy2 23}] &[{zcy 12} {zcy2 23}]
1   location is 0xc00099ab70 
1.1 location is 0xc00099ab70 
1.2 location is 0xc00099ab88 
2   location is 0xc00099bb00 
2.1 location is 0xc00099bb00 
2.2 location is 0xc00099bb18 
[{zcy1 2} {zcy2 32}] &[{zcy1 2} {zcy2 32}]
1   location is 0xc00031cc80 
1.1 location is 0xc00099bc50 
1.2 location is 0xc00099bc68 
2   location is 0xc00031ce80 
2.1 location is 0xc00099bc50 
2.2 location is 0xc00099bc68 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Go语言基本语法和高级变量类型的介绍: 1. 变量声明和初始化 在Go语言中,可以使用var关键字声明变量。变量声明可以包含一个或多个变量,可以在声明时初始化变量,也可以在后续代码中初始化变量。例如: ```go var name string var age int = 18 married := false ``` 2. 数据类型 Go语言中的数据类型包括基本数据类型和复合数据类型。基本数据类型包括bool、string、int、float等,复合数据类型包括数组、切片、结构体、接口、函数等。例如: ```go // 基本数据类型 var b bool = true var s string = "hello" var i int = 10 var f float32 = 3.14 // 复合数据类型 var arr [3]int = [3]int{1, 2, 3} var slice []int = []int{1, 2, 3} type Person struct { Name string Age int } var p Person = Person{Name: "Tom", Age: 18} ``` 3. 指针类型 Go语言中的指针类型用于存储变量的内存地址。可以使用&运算符获取变量的地址,使用*运算符获取指针指向的变量的值。例如: ```go var i int = 10 var p *int = &i fmt.Println(*p) // 输出:10 ``` 4. 结构体类型 Go语言中的结构体类型用于定义一组相关的数据字段。可以使用type关键字定义结构体类型,使用.运算符访问结构体字段。例如: ```go type Person struct { Name string Age int } var p Person = Person{Name: "Tom", Age: 18} fmt.Println(p.Name) // 输出:Tom ``` 5. 接口类型 Go语言中的接口类型用于定义一组方法签名。可以使用type关键字定义接口类型,使用实现接口的类型来实现接口方法。例如: ```go type Animal interface { Speak() string } type Dog struct {} func (d Dog) Speak() string { return "汪汪" } var a Animal = Dog{} fmt.Println(a.Speak()) // 输出:汪汪 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值