
头条真实面试题
struct结构体能不能比较
结构体不可以比较,但是同一类型的结构体的值可以比较是否相等的(不可以比较大小):
结构体所有字段的值都相等,两个结构体才相等
比较的两个结构体必须是相同类型才可以,也就是说他们字段的顺序、名称、类型、标签都相同才可以
struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套;
go中的struct类型理解为类,可以定义方法,和函数定义有些许区别;
struct类型是值类型。
struct定义
type User struct {Name stringAge int32mess string}
var user Uservar user1 *User = &User{}var user2 *User = new(User)
struct使用
下面示例中user1和user2为指针类型,访问的时候编译器会自动把 user1.Name 转为 (*user1).Name
func main() {var user Useruser.Name = "nick"user.Age = 18user.mess = "lover"var user1 *User = &User{Name: "dawn",Age: 21,}fmt.Println(*user1) //{dawn 21 }fmt.Println(user1.Name, (*user1).Name) //dawn dawnvar user2 *User = new(User)user2.Name = "suolong"user2.Age = 18fmt.Println(user2) //&{suolong 18 }fmt.Println(user2.Name, (*user2).Name)}
构造函数
golang中的struct没有构造函数,可以伪造一个
type User struct {Name stringAge int32mess string}func NewUser(name string, age int32, mess string) *User {return &User{Name:name,Age:age,mess:mess}}func main() {//user := new(User)user := NewUser("suolong", 18, "lover")fmt.Println(user, user.mess, user.Name, user.Age)}
内存布局
struct中的所有字段在内存是连续的
var user Useruser.Name = "nick"user.Age = 18user.mess = "lover"fmt.Println(user) //{nick 18 lover}fmt.Printf("Name:%p\n", &user.Name) //Name:0xc420016180fmt.Printf("Age: %p\n", &user.Age) //Age: 0xc420016190fmt.Printf("mess:%p\n", &user.mess) //mess:0xc420016198 8字节为内存对齐
方法
方法是作用在特定类型的变量上,因此自定义类型,都可以有方法,而不仅仅是struct。
方法的访问控制也是通过大小写控制。
init函数是通过传入指针实现,这样改变struct字段值,因为是值类型。
type User struct {Name stringAge intsex string}func (this *User) init(name string, age int, sex string) {this.Name = namethis.Age = agethis.sex = sex}func (this User) GetName() string {return this.Name}func main() {var user Useruser.init("nick", 18, "man")//(&user).init("nick", 18, "man")name := user.GetName()fmt.Println(name)}
匿名字段
如果有冲突的, 则最外层的优先
type User struct {Name stirngAge int}type Lover struct {Usersex time.TimeintAge int}
继承 & 多重继承
一个结构体继承多个结构体,访问通过点。继承字段以及方法。
可以起别名,如下面 u1(user1),访问 user.u1.Age。
如果继承的结构体都拥有同一个字段,通过user.name访问就会报错,必须通过user.user1.name来访问。
type user1 struct {name stringAge int}type user2 struct {name stringage intsex time.Time}type User struct {u1 user1 //别名user2Name stringAge int}func main() {var user Useruser.Name = "nick"user.u1.Age = 18fmt.Println(user) //{{ 18} { 0 {0 0 <nil>}} nick 0}}
tag
在go中,首字母大小写有特殊的语法含义,小写包外无法引用。由于需要和其它的系统进行数据交互,例如转成json格式。这个时候如果用属性名来作为键值可能不一定会符合项目要求。tag在转换成其它数据格式的时候,会使用其中特定的字段作为键值。
import "encoding/json"type User struct {Name string `json:"userName"`Age int `json:"userAge"`}func main() {var user Useruser.Name = "nick"user.Age = 18conJson, _ := json.Marshal(user)fmt.Println(string(conJson)) //{"userName":"nick","userAge":0}}
String()
如果实现了String()这个方法,那么fmt默认会调用String()。
type name1 struct {intstring}func (this *name1) String() string {return fmt.Sprintf("This is String(%s).", this.string)}func main() {n := new(name1)fmt.Println(n) //This is String().n.string = "suolong"d := fmt.Sprintf("%s", n) //This is String(suolong).fmt.Println(d)}
recover()
defer 所有错误
func myE() (str string, err error) {defer func() {if p := recover(); p != nil {str, ok := p.(string)if ok {err = errors.New(str)} else {err = errors.New("panic")}//debug.PrintStack()}}()panic("this is panic message")return "hello girl", err}
