Skip to content

类型、结构体相关题目 #49

Open
@JasonJe

Description

@JasonJe
  1. 新类型和类型别名
package main

import "fmt"

type MyInt1 int
type MyInt2 = int

func main() {
    var i int =0
    var i1 MyInt1 = i 
    var i2 MyInt2 = i
    fmt.Println(i1,i2)
}

解析:type MyInt1 int 是基于int类型创建了新类型,而type MyInt2 = int 是创建了 int 类型的别名MyInt2

var i1 MyInt1 = i 是将int类型的变量赋值给MyInt1Go是强类型的语言,编译不能通过,正确的做法是进行强制类型转换,即var i1 MyInt1 = MyInt1(i);而MyInt2int的别名,能够进行赋值。

  1. 下面代码能否通过编译
func GetValue() int {
    return 1
}

func main() {
    i := GetValue()
    switch i.(type) {
    case int:
        println("int")
    case string:
        println("string")
    case interface{}:
        println("interface")
    default:
        println("unknown")
    }
}

结果:不能通过编译。

解析:只有接口类型才能进行类型选择。

  1. 下面的代码输出是什么
func main() {  
    a := 5
    b := 8.1
    fmt.Println(a + b)
}

解析:编译出错,Go语言是强类型语言,不同类型之间不能直接相加。

  1. 下面的代码能正常编译吗
func (i int) PrintInt ()  {
    fmt.Println(i)
}

func main() {
    var i int = 1
    i.PrintInt()
}

解析:编译错误。基于类型创建的方法必须定义在同一个包内;解决的办法可以定义一种新的类型。即:

type Myint int

func (i Myint) PrintInt ()  {
    fmt.Println(i)
}

func main() {
    var i Myint = 1
    i.PrintInt()
}
  1. 下面的代码能正常编译吗
type People interface {
    Speak(string) string
}

type Student struct{}

func (stu *Student) Speak(think string) (talk string) {
    if think == "speak" {
        talk = "speak"
    } else {
        talk = "hi"
    }
    return
}

func main() {
    var peo People = Student{}
    think := "speak"
    fmt.Println(peo.Speak(think))
}

解析:编译错误。值类型 Student 没有实现接口的 Speak() 方法,而是指针类型 *Student 实现该方法。

  1. 判断下面代码能否通过编译
func main() {
    sn1 := struct {
        age  int
        name string
    }{age11name: "qq"}
    sn2 := struct {
        age  int
        name string
    }{age11name: "qq"}

    if sn1 == sn2 {
        fmt.Println("sn1 == sn2")
    }

    sm1 := struct {
        age int
        m   map[string]string
    }{age11mmap[string]string{"a": "1"}}
    sm2 := struct {
        age int
        m   map[string]string
    }{age11mmap[string]string{"a": "1"}}

    if sm1 == sm2 {
        fmt.Println("sm1 == sm2")
    }
}
  • 结构体只能比较是否相等,但是不能比较大小。

  • 相同类型的结构体才能够进行比较,结构体是否相同不但与属性类型有关,还与属性顺序相关。下面的sn3 与 sn1 就是不同的结构体:

sn3:= struct {
    name string
    age  int
}{age:11,name:"qq"}
  • 如果 struct 的所有成员都可以比较,则该 struct 就可以通过 ==!= 进行比较是否相等,比较时逐个项进行比较,如果每一项都相等,则两个结构体才相等,否则不相等。
  1. 下面的代码能正常编译吗
type People interface {
    Show()
}

type Student struct{}

func (stu *Student) Show() {

}

func main() {

    var s *Student
    if s == nil {
        fmt.Println("s is nil")
    } else {
        fmt.Println("s is not nil")
    }
    var p People = s
    if p == nil {
        fmt.Println("p is nil")
    } else {
        fmt.Println("p is not nil")
    }
}

解析:输出:s is nilp is not nil。当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil。上面的代码,给变量 p 赋值之后,p 的动态值是 nil,但是动态类型却是 *Student,是一个 nil 指针,所以相等条件不成立。

  1. 下面代码输出什么
func main() {
    x := interface{}(nil)
    y := (*int)(nil)
    a := y == x
    b := y == nil
    _, c := x.(interface{})
    println(a, b, c)
}

输出:false true false

解析:类型断言语法:i.(Type),其中 i 是接口,Type 是类型或接口。编译时会自动检测 i 的动态类型与 Type 是否一致。但是,如果动态类型不存在,则断言总是失败。

  1. 下面代码能编译通过吗
type info struct {
    result int
}

func work() (int,error) {
    return 13,nil
}

func main() {
    var data info

    data.result, err := work() 
    fmt.Printf("info: %+v\n",data)
}

解析:编译失败。non-name data.result on left side of :=。不能使用短变量声明设置结构体字段值。

修复代码:

func main() {
    var data info

    var err error
    data.result, err = work() //ok
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(data)   
}
  1. 下面这段代码输出什么
type People struct {
    name string `json:"name"`
}

func main() {
    js := `{
        "name":"seekload"
    }`
    var p People
    err := json.Unmarshal([]byte(js), &p)
    if err != nil {
        fmt.Println("err: ", err)
        return
    }ex
    fmt.Println(p)
}

输出:struct field name has json tag but is not exported

解析:结构体访问控制,因为 name 首字母是小写,导致其他包不能访问。

  1. 下面这段代码输出什么
type T struct {
    ls []int
}

func foo(t T) {
    t.ls[0] = 100
}

func main() {
    var t = T{
        ls: []int{1, 2, 3},
    }

    foo(t)
    fmt.Println(t.ls[0])
}

输出:100

解析:调用 foo() 函数时虽然是传值,但 foo() 函数中,字段 ls 依旧可以看成是指向底层数组的指针。

  1. 下面的代码有什么问题
type X struct {}

func (x *X) test()  {
    println(x)
}

func main() {

    var a *X
    a.test()

    X{}.test()
}

解析:X{} 是不可寻址的,不能直接调用方法。在方法中,指针类型的接收者必须是合法指针(包括 nil),或能获取实例地址。

  1. 下面的代码输出什么
type T struct {
    x int
    y *int
}

func main() {
    i := 20
    t := T{10,&i}

    p := &t.x // 先计算 t.x ,然后得到 t.x 的地址

    *p++ // 先获取 p 的值,然后累加
    *p-- // 同上,做递减

    t.y = p

    fmt.Println(*t.y) // 取值
}

输出:10

解析:递增运算符 ++ 和递减运算符 -- 的优先级低于解引用运算符 * 和取址运算符 &,解引用运算符和取址运算符的优先级低于选择器 . 中的属性选择操作符。

  1. 下面的代码输出什么
type N int

func (n *N) test(){
    fmt.Println(*n)
}

func main()  {
    var n N = 10
    p := &n

    n++
    f1 := n.test

    n++
    f2 := p.test

    n++
    fmt.Println(n)

    f1()
    f2()
}

输出:13 13 13

解析:当目标方法的接收者是指针类型时,那么被复制的就是指针。

  1. 下面哪一行代码会 panic
package main

type T struct{}

func (*T) foo() {
}

func (T) bar() {
}

type S struct {
  *T
}

func main() {
  s := S{}
  _ = s.foo
  s.foo()
  _ = s.bar
}

解析:_ = s.bar行。因为 s.bar 将被展开为 (*s.T).bar,而 s.T 是个空指针,解引用会 panic

  1. 下面哪一行代码会 panic
func main() {
    nil := 123
    fmt.Println(nil)
    var _ map[string]int = nil
}

解析:var _ map[string]int = nil行。当前作用域中,预定义的 nil 被覆盖,此时 nilint 类型值,不能赋值给 map 类型。

  1. 下面的代码输出什么

17.1

type T struct {
    n int
}

func main() {
    ts := [2]T{}
    for i, t := range ts {
        switch i {
        case 0:
            t.n = 3
            ts[1].n = 9
        case 1:
            fmt.Print(t.n, " ")
        }
    }
    fmt.Print(ts)
}

输出:0 [{0} {9}]

解析:此时 for-range 使用的是数组 ts 的副本,所以 t.n = 3 的赋值操作不会影响原数组。

17.2

type T struct {
    n int
}

func main() {
    ts := [2]T{}
    for i, t := range &ts {
        switch i {
        case 0:
            t.n = 3
            ts[1].n = 9
        case 1:
            fmt.Print(t.n, " ")
        }
    }
    fmt.Print(ts)
}

输出:9 [{0} {9}]

解析:for-range 循环中的循环变量 t 是原数组元素的副本。如果数组元素是结构体值,则副本的字段和原数组字段是两个不同的值。

17.3

type T struct {
    n int
}

func main() {
    ts := [2]T{}
    for i := range ts[:] {
        switch i {
        case 0:
            ts[1].n = 9
        case 1:
            fmt.Print(ts[i].n, " ")
        }
    }
    fmt.Print(ts)
}

输出:9 [{0} {9}]

解析:for-range 切片时使用的是切片的副本,但不会复制底层数组,所以此副本切片与原数组共享底层数组。

Metadata

Metadata

Assignees

No one assigned

    Labels

    GoGolang

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions