结构体

一个程序就是一个世界,有很多对象变量

golang语言面向对象编程说明

  • golang也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。所以说golang支持面向对象编程特性是比较准确的
  • golang没有类(class),go语言的结构体(struct)和其它编程语言的类(class)有同等的地位,可以理解golang是基于struct来实现OOP特性
  • golang面向对象编程非常简洁,去掉了传统OOP语言的继承、方法重载、构造函数和析构函数、隐藏的this指针等等
  • golang仍然有面向对象编程的继承封装多态的特性,只是实现的方式和其它OOP语言不同,比如继承: golang没有extends关键字,继承是通过匿名字段来实现
  • golang面向对象(OOP)很优雅,OOP本身就是语言类型系统(type system)的一部分,通过接口(interface)关联,耦合性低,也非常灵活。在golang中面向接口编程是非常重要的特性

结构体与结构体变量(实例/对象)的关系


说明:

  1. 将一类事物的特性提取出来(比如猫类),形成一个新的数据类型,就是一个结构体
  2. 通过这个结构体,可以创建多个变量(实例/对象
  3. 事物可以是各种类

从猫结构体到变量,就是创建一个Cat结构体变量,也可以说是定义一个Cat结构体变量

package mainimport "fmt"type Cat struct {Name stringAge intColor string
}
func main() {var cat1 Catcat1.Name = "小白"cat1.Age = 3cat1.Color = "白色"fmt.Println("cat1=", cat1)fmt.Println("name=", cat1.Name)fmt.Println("Age=", cat1.Age)fmt.Println("color=", cat1.Color)
}

结构体和结构体变量(实例)的区别和联系

  • 结构体是自定义的数据类型,代表一类事物
  • 结构体变量(实例)是具体的,代表一个具体变量

结构体变量(实例)在内存的布局(重要!)

声明结构体

type 结构体名称 struct {field1 typefield2 type...
}
type Student struct {Name stringAge intScore float32
}

字段/属性

基本介绍

  • 从概念或叫法上看: 结构体字段 = 属性 = field
  • 字段是结构体的一个组成部分,一般是基本数据类型、数组,也可以是引用类型

注意事项

  • 字段声明语法同变量, 字段名 字段类型
  • 字段的类型可以为: 基本类型、数组或引用类型
  • 在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值(默认值), 布尔类型是false, 数值是 0, 字符串是 “”, 数组类型的默认值和它的元素类型相关 , 指针slice, 和 map 的零值都是 nil, 即还没有分配空间
package mainimport "fmt"type Person struct {Name stringAge intScores [5]float64ptr *intslice []intmap1 map[string]string
}func main() {var p1 Personfmt.Println(p1)if p1.ptr == nil {fmt.Println("ok1")}if p1.slice == nil {fmt.Println("ok2")}if p1.map1 == nil {fmt.Println("ok3")}p1.slice = make([]int, 10)p1.slice[0] = 100p1.map1 = make(map[string]string)p1.map1["key1"] = "tom"fmt.Println(p1)
}
  • 不同结构体变量的字段是独立,互不影响,一个结构体变量字段的更改,不影响另外一个,结构体是值类型
package mainimport "fmt"type Monster struct {Name stringAge int
}func main() {var monster1 Monstermonster1.Name = "牛魔王"monster1.Age = 500monster2 := monster1monster2.Name = "青牛精"fmt.Println("monster1=", monster1)fmt.Println("monster2=", monster2)
}

运行结果

monster1= {牛魔王 500}
monster2= {青牛精 500}

创建结构体变量和访问结构体字段

  • 方式1- 直接声明
  • 方式2- {}
var person Person = Person{}
package mainimport "fmt"type Person struct {Name stringAge int
}func main() {p2 := Person{"mary", 20}fmt.Println(p2)
}
  • 方式3- &
var person *Person = new(Person)
package mainimport "fmt"type Person struct {Name stringAge int
}func main() {var p3 *Person = new(Person)// (*p3).Name = "smith" 等价  p3.Name = "smith"//go设计者为了方便,底层对p3.Name = "smith" 进行处理,(*p3).Name = "smith"(*p3).Name = "smith"p3.Name = "john"(*p3).Age = 30p3.Age = 100fmt.Println(*p3)
}
  • 方式4- {}
var person *Person = &Person{}
package mainimport "fmt"type Person struct {Name stringAge int
}func main() {var person *Person = &Person{}(*person).Name = "scott"person.Name = "tom"(*person).Age = 88person.Age = 10fmt.Println(*person)
}

说明:

  1. 第3种和第4种方式返回的是 结构体指针
  2. 结构体指针访问字段的标准方式: (*结构体指针).字段名 比如 (*person).Name = “tom”
  3. 但go做了一个简化,也支持 结构体指针.字段名 比如 person.Name = “tom” 更加符合程序员使用的习惯,go编译器底层对 person.Name 做了转化 (*person).Name

struct类型的内存分配机制

package mainimport "fmt"type Person struct {Name stringAge int
}func main() {var p1 Personp1.Age = 10p1.Name = "小明"var p2 Person = p1fmt.Println(p2.Age)p2.Name = "tom"fmt.Printf("p2.Name=%v p1.Name=%v", p2.Name, p1.Name)
}

package mainimport "fmt"type Person struct {Name stringAge int
}func main() {var p1 Personp1.Age = 10p1.Name = "小明"var p2 *Person = &p1fmt.Println((*p2).Age)fmt.Println(p2.Age)p2.Name = "tom"fmt.Printf("p2.Name=%v p1.Name=%v\n", p2.Name, p1.Name)fmt.Printf("p2.Name=%v p1.Name=%v\n", (*p2).Name, p1.Name)fmt.Printf("p1的地址%p\n", &p1)fmt.Printf("p2的地址%p  p2的值%p\n", &p2, p2)
}

运行结果

10
10
p2.Name=tom p1.Name=tom
p2.Name=tom p1.Name=tom
p1的地址0xc04203e3a0
p2的地址0xc042062018  p2的值0xc04203e3a0

结构体使用注意事项

  • 结构体的所有字段在内存中是连续
package mainimport "fmt"type Point struct {x inty int
}
type Rect struct {leftUp, rightDown Point
}
type Rect2 struct {leftUp, rightDown *Point
}func main() {r1 := Rect{Point{1, 2}, Point{3, 4}}//r1有四个int, 在内存中是连续分布//打印地址fmt.Printf("r1.leftUp.x 地址=%p r1.leftUp.y 地址=%p r1.rightDown.x 地址%p r1.rightDown.y 地址=%p\n", &r1.leftUp.x, &r1.leftUp.y, &r1.rightDown.x, &r1.rightDown.y)r2 := Rect2{&Point{10, 20}, &Point{30, 40}}//打印地址fmt.Printf("r2.leftUp 本身地址=%p r2.rightDown 本身地址=%p \n", &r2.leftUp, &r2.rightDown)fmt.Printf("r2.leftUp 指向地址=%p r2.rightDown 指向地址=%p \n", r2.leftUp, r2.rightDown)
}

运行结果

r1.leftUp.x 地址=0xc0420420a0 r1.leftUp.y 地址=0xc0420420a8 r1.rightDown.x 地址0xc0420420b0 r1.rightDown.y 地址=0xc0420420b8
r2.leftUp 本身地址=0xc0420381b0 r2.rightDown 本身地址=0xc0420381b8
r2.leftUp 指向地址=0xc042044090 r2.rightDown 指向地址=0xc0420440a0

  • 结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段名字、个数 和 类型
package mainimport "fmt"type A struct {Num int
}
type B struct {Num int
}func main() {var a Avar b Ba = A(b)fmt.Println(a, b)
}
  • 结构体进行type重新定义(相当于取别名),golang认为是新的数据类型,但是相互间可以强转

  • struct的每个字段上,可以写上一个tag, 该tag可以通过反射机制获取,常见的使用场景就是序列化反序列化

package mainimport ("encoding/json""fmt"
)type Monster struct {Name string `json:"name"` // `json:"name"` 就是 struct tagAge int `json:"age"`Skill string `json:"skill"`
}func main() {monster := Monster{"牛魔王", 500, "芭蕉扇"}fmt.Println(monster)//json.Marshal 函数中使用反射jsonStr, err := json.Marshal(monster)if err != nil {fmt.Println("json 处理错误 ", err)}fmt.Println("jsonStr", string(jsonStr))
}

运行结果

{牛魔王 500 芭蕉扇}
jsonStr {"name":"牛魔王","age":500,"skill":"芭蕉扇"}

方法

在某些情况下,需要声明(定义)方法。比如Person结构体:除了有一些字段外(年龄,姓名,…),Person结构体还有一些行为 比如:说话、跑步…,通过学习,还可以做算术题。就要用方法才能完成

golang中的方法是作用在指定的数据类型上的(即: 和指定的数据类型绑定),因此自定义类型都可以有方法,而不仅仅是struct

方法的声明和调用

type A struct {Num int
}
func (a A) test() {fmt.Println(a.Num)
}

说明:

  1. func (a A) test() {} 表示A结构体有一方法,方法名为 test
  2. (a A) 体现test方法是和 A类型绑定的
package mainimport "fmt"type Person struct {Name string
}func (p Person) test() {p.Name = "jack"fmt.Println("test() p.Name=", p.Name)
}func main() {var p Personp.Name = "tom"p.test()fmt.Println("main() p.Name=", p.Name)
}

运行结果

test() p.Name= jack
main() p.Name= tom

说明:

  1. test方法和Person类型绑定
  2. test方法只能通过Person类型的变量来调用,而不能直接调用,也不能使用其它类型变量来调用
  3. func (p Person) test() {}… p表示哪个Person变量调用,这个p就是它的副本,这点和函数传参非常相似
  4. p这个名字,由程序员指定, 不是固定的
package mainimport "fmt"type Person struct {Name string
}func (person Person) test() {fmt.Println("test() name=", person.Name)
}
func main() {var person Personperson.Name = "tom"person.test() //调用方法
}

方法快速入门

  • 给Person结构体添加speak方法, 输出信息
package mainimport "fmt"type Person struct {Name string
}func (p Person) speak() {fmt.Println(p.Name, "是一个goodman")
}
func main() {var p Personp.Name = "tom"p.speak() //调用方法
}
  • 给Person结构体添加jisuan方法,可以计算 1+…+1000的结果,说明方法体内可以函数一样,进行各种运算
package mainimport "fmt"type Person struct {Name string
}func (p Person) speak() {fmt.Println(p.Name, "是一个goodman")
}
func (p Person) jisuan() {res := 0for i := 1; i <= 1000; i++ {res += i}fmt.Println(p.Name, "计算结果是=", res)
}
func main() {var p Personp.Name = "tom"p.jisuan() //调用方法
}
  • 给Person结构体jisuan2方法,该方法可以接收一个数n,计算 1+…+n 的结果
package mainimport "fmt"type Person struct {Name string
}func (p Person) jisuan2(n int) {res := 0for i := 1; i <= n; i++ {res += i}fmt.Println(p.Name, "计算结果是=", res)
}
func main() {var p Personp.Name = "tom"p.jisuan2(100) //调用方法
}
  • 给Person结构体添加getSum方法,可以计算两个数的和,并返回结果
package mainimport "fmt"type Person struct {Name string
}func (p Person) getSum(n1 int, n2 int) (int) {return n1 + n2
}
func main() {var p Personres := p.getSum(10, 20) //调用方法fmt.Println("res=", res)
}

方法的调用和传参机制原理(重要!)

方法的调用和传参机制和函数基本一样,不一样的地方时方法调用时,会将调用方法的变量,当做实参也传递给方法


说明:

  1. 在通过一个变量去调用方法时,其调用机制和函数一样
  2. 不一样的地方是,变量调用方法时,该变量本身也会作为一个参数传递到方法(如果变量是值类型,则进行值拷贝,如果变量是引用类型,则进行地址拷贝

编写一个程序,要求如下:
1 声明一个结构体Circle,字段为radius
2 声明一个方法area和Circle绑定,可以返回面积

package mainimport "fmt"type Circle struct {radius float64
}func (c Circle) area() (float64) {return 3.14 * c.radius * c.radius
}
func main() {var c Circlec.radius = 4.0res := c.area()fmt.Println("area=", res)
}

方法的声明(定义)

func (recevier type) methodName(参数列表) (返回值列表) {方法体return 返回值
}
  • 参数列表: 表示方法输入
  • recevier type: 表示这个方法和type这个类型进行绑定,或者说该方法作用于type类型
  • recevier type: type可以是结构体, 也可以其它的自定义类型
  • recevier: 就是type类型的一个变量(实例), 比如: Person结构体的一个变量(实例)
  • 返回值类型列表:表示返回的值,可以多个
  • 方法主体: 表示为了实现某一功能代码块
  • return语句不是必须的

方法的注意事项

  • 结构体类型是值类型, 在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
  • 在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理
package mainimport "fmt"type Circle struct {radius float64
}func (c *Circle) area() (float64) {c.radius = 10.0return 3.14 * c.radius * c.radius
}
func main() {var c Circlec.radius = 4.0//res := (&c).area()//编译器底层做了优化 (&c).area() 等价 c.area()//编译器会自动给加上 &cres := c.area()fmt.Println("area=", res)fmt.Println("c.radius= ",c.radius)
}

  • golang中的方法作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct, 比如 int, float32等都可以有方法
package mainimport "fmt"type integer intfunc (i integer) print() {fmt.Println("i=", i)
}
func (i *integer) change() {*i = *i + 1
}
func main() {var i integer = 10i.print()i.change()fmt.Println("i=", i)
}
  • 方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问
  • 如果一个类型实现了String()这个方法,那么 fmt.Println默认会调用这个变量的String()进行输出
package mainimport "fmt"type Student struct {Name stringAge int
}
//给*Student实现方法String()
func (stu *Student) String() (string) {str := fmt.Sprintf("Name=[%v] Age=[%v]", stu.Name, stu.Age)return str
}
func main() {//定义一个Student变量stu := Student{Name: "tom",Age:  20,}//如果实现了 *Student类型的 String方法,就会自动调用fmt.Println(&stu)
}

编写结构体(MethodUtils),编写一个方法,方法不需要参数,在方法中打印一个10*8的矩形,在main方法中调用该方法

package mainimport "fmt"type MethodUtils struct {}func (mu MethodUtils) Print() {for i := 0; i < 10; i++ {for j := 0; j < 8; j++ {fmt.Print("*")}fmt.Println()}
}
func main() {var mu MethodUtilsmu.Print()
}

编写一个方法,提供m和n两个参数,方法中打印一个m*n的矩形

package mainimport "fmt"type MethodUtils struct {}func (mu MethodUtils) Print2(m int, n int)  {for i := 0; i < m; i++ {for j := 0; j < n; j++ {fmt.Print("*")}fmt.Println()}
}
func main() {var mu MethodUtilsmu.Print2(3, 4)
}

编写一个方法算该矩形的面积(可以接收长len , 宽 width),将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印

package mainimport "fmt"type MethodUtils struct {}func (mu MethodUtils) area(len float64, width float64) (float64) {return len * width
}
func main() {var mu MethodUtilss := mu.area(10, 15)fmt.Println("面积 s=", s)
}

编写方法:判断一个数是奇数还是偶数

package mainimport "fmt"type MethodUtils struct {Num int
}func (mu *MethodUtils) JudgeNum(num int) {if num % 2 == 0 {fmt.Println(num, "是偶数")} else {fmt.Println(num, "是奇数")}
}
func main() {var mu MethodUtilsmu.Num = 46mu.JudgeNum(mu.Num)
}

根据行、列、字符打印对应行数和列数的字符

package mainimport "fmt"type MethodUtils struct {}func (mu *MethodUtils) Print3(n int, m int, key string) {for i := 0; i < n; i++ {for j := 0; j < m; j++ {fmt.Print(key)}fmt.Println()}
}
func main() {var mu MethodUtilsmu.Print3(3,5, "#")
}

定义计算器结构体(Calcuator),实现加减乘除四个功能

package mainimport "fmt"type Calcuator struct {Num1 float64Num2 float64
}func (calcuator *Calcuator) getSum() float64 {return calcuator.Num1 + calcuator.Num2
}
func (calcuator *Calcuator) getSub() float64 {return calcuator.Num1 - calcuator.Num2
}
func main() {var calcuator Calcuatorcalcuator.Num1 = 1.2calcuator.Num2 = 2.2fmt.Printf("sum=%v\n", fmt.Sprintf("%.2f", calcuator.getSum()))fmt.Printf("sub=%v\n", fmt.Sprintf("%.2f", calcuator.getSub()))
}
package mainimport "fmt"type Calcuator struct {Num1 float64Num2 float64
}func (calcuator *Calcuator) getRes(operator byte) (float64) {res := 0.0switch operator {case '+':res = calcuator.Num1 + calcuator.Num2case '-':res = calcuator.Num1 - calcuator.Num2case '*':res = calcuator.Num1 * calcuator.Num2case '/':res = calcuator.Num1 / calcuator.Num2default:fmt.Println("运算符有误...")}return res
}
func main() {var calcuator Calcuatorcalcuator.Num1 = 8calcuator.Num2 = 4res := calcuator.getRes('+')fmt.Println("res=", res)
}

在MethodUtils结构体编写方法,从键盘接收整数(1-9),打印对应乘法表

package mainimport "fmt"type MethodUtils struct {Num int
}func (mu MethodUtils) tab99(num int) {for i := 1; i <= num; i++ {for j := 1; j <= i; j++ {fmt.Printf("%v*%v=%v\t", j, i, j * i)}fmt.Println()}
}
func main() {var mu MethodUtilsfmt.Println("请输入整数1-9: ")fmt.Scanln(&mu.Num)mu.tab99(mu.Num)
}

编写方法,使给定的二维数组(3X3)转置

package mainimport "fmt"type MethodUtils struct {}func (mu MethodUtils) Arr(arr *[3][3]int) {temp := [3][3]int{}for i := 0; i < len(arr); i++ {for j := 0; j < i; j++ {temp[i][j] = arr[i][j]arr[i][j] = arr[j][i]arr[j][i] = temp[i][j]}}
}
func main() {var mu MethodUtilsvar arr [3][3]int = [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}fmt.Println("转置前")for i := 0; i < 3; i++ {for j := 0; j < 3; j++ {fmt.Printf("%v\t", arr[i][j])}fmt.Println()}mu.Arr(&arr)fmt.Println("转置后")for i := 0; i < 3; i++ {for j := 0; j < 3; j++ {fmt.Printf("%v\t", arr[i][j])}fmt.Println()}
}

方法和函数的区别

  1. 调用方式不一样
    函数的调用方式: 函数名(实参列表)
    方法的调用方式: 变量.方法名(实参列表)
  2. 对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
package mainimport "fmt"type Person struct {Name string
}func test01(p Person)  {fmt.Println(p.Name)
}
func test02(p *Person)  {fmt.Println(p.Name)
}
func main() {p := Person{"tom"}test01(p)test02(&p)
}
  1. 对于方法(如 struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以
package mainimport "fmt"type Person struct {Name string
}func (p Person) test03() {p.Name = "jack"fmt.Println("test03()=", p.Name)
}func (p *Person) test04() {p.Name = "mary"fmt.Println("test04()=", p.Name)
}
func main() {p := Person{"tom"}p.test03()fmt.Println("main() p.Name=", p.Name)(&p).test03() //仍然是值拷贝fmt.Println("main() p.Name=", p.Name)p.test04()  //等价 (&p).test04()fmt.Println("main() p.Name=", p.Name)(&p).test04()fmt.Println("main() p.Name=", p.Name)
}

说明:

  1. 不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和哪个类型绑定
  2. 如果是和值类型绑定,比如 (p Person), 则是值拷贝, 如果和指针类型绑定, 比如 (p *Person) 则是地址拷贝

面向对象编程应用实例

编写一个Student结构体,包含name, gender, age, id, score 字段,分别为 string,string, int, int, float64类型
结构体中声明一个say方法,返回string类型,方法返回信息中包含所有字段值
在main方法中,创建Student结构体实例(变量),并访问say方法,并将调用结果打印输出

package mainimport "fmt"type Student struct {name stringgender stringage intid intscore float64
}func (student *Student) say() (string) {infoStr := fmt.Sprintf("student信息 name=%v gender=%v age=%v id=%v score=%v", student.name, student.gender, student.age, student.id, student.score)return infoStr
}
func main() {var stu = Student{name:   "tom",gender: "male",age:    18,id:     1000,score:  99.98,}fmt.Println(stu.say())
}
package mainimport "fmt"type Dog struct {name stringage intweight float64
}func (dog *Dog) say() (string) {infoDog := fmt.Sprintf("dog info name=%v age=%v weight=%v", dog.name, dog.age, dog.weight)return infoDog
}
func main() {var dog = Dog{name:   "哮天犬",age:    300,weight: 89.56,}fmt.Println(dog.say())
}

盒子案例

创建一个Box结构体,在其中声明三个字段表示立方体的长、宽、高
声明一个方法获取立方体的体积
创建一个Box结构体变量,打印给定尺寸的立方体体积

package mainimport "fmt"type Box struct {len float64width float64height float64
}func (box Box) getVolume() (float64) {return box.len * box.width * box.height
}
func main() {var box Boxbox.len = 1.1box.width = 2.0box.height = 3.0volume := box.getVolume()fmt.Printf("体积为=%.2f", volume)
}

一个景区根据游人的年龄收取不同价格的门票,比如大于18,收费20元,其它情况门票免费
编写Visitor结构体,根据年龄段决定能够购买的门票价格并输出

package mainimport "fmt"type Visitor struct {Name stringAge int
}func (visitor Visitor) price() {if visitor.Age >= 90 || visitor.Age <= 8 {fmt.Println("考虑到安全,不要玩耍")return}if visitor.Age > 18 {fmt.Printf("游客名字为 %v 年龄为 %v  收费20\n", visitor.Name, visitor.Age)} else {fmt.Printf("游客名字为 %v 年龄为 %v 免费\n", visitor.Name, visitor.Age)}
}
func main() {var v Visitorfor  {fmt.Println("请输入你的名字: ")fmt.Scanln(&v.Name)if v.Name == "n" {fmt.Println("退出程序...")break}fmt.Println("请输入你的年龄: ")fmt.Scanln(&v.Age)v.price()}
}

创建结构体变量时指定字段值

golang在创建结构体实例(变量)时,可以直接指定字段的值

  • 方式1
package mainimport "fmt"type Stu struct {Name stringAge int
}func main() {var stu1 = Stu{"小明", 19}stu2 := Stu{"小明", 20}var stu3 = Stu{Name: "jack",Age:  20,}stu4 := Stu{Name: "mary",Age:  30,}fmt.Println(stu1, stu2, stu3, stu4)
}
  • 方式2
package mainimport "fmt"type Stu struct {Name stringAge int
}func main() {var stu5 *Stu = &Stu{"张三", 29}stu6 := &Stu{"李四", 39}var stu7 = &Stu{Name: "王五",Age:  49,}stu8 := &Stu{Name: "赵六",Age:  59,}fmt.Println(*stu5, *stu6, *stu7, *stu8)
}

工厂模式

golang的结构体没有构造函数,通常可以使用工厂模式来解决这个问题

package model
type Student struct {Name string
}

这里的Student的首字母S是大写的,如果想在其它包创建Student的实例(比如main 包),引入model包后,就可以直接创建Student结构体的变量(实例). 如果首字母是小写的,就不行了 ------> 工厂模式

student.go

package modeltype student struct {Name stringScore float64
}func NewStudent(n string, s float64) *student {return &student{Name:  "n",Score: s,}
}

main.go

package mainimport ("fmt""go_code/project01/model"
)func main() {var stu = model.NewStudent("tom", 88.8)fmt.Println(*stu) //&{...}fmt.Println("name= ", stu.Name, "score=", stu.Score)
}

如果model包得student的结构体的字段Score 改为 score
student.go

package modeltype student struct {Name stringscore float64
}func NewStudent(n string, s float64) *student {return &student{Name:  "n",score: s,}
}
func (s *student) GetScore() float64 {return s.score
}

main.go

package mainimport ("fmt""go_code/project01/model"
)func main() {var stu = model.NewStudent("tom", 88.8)fmt.Println(*stu) //&{...}fmt.Println("name= ", stu.Name, "score=", stu.GetScore())
}

go 面向对象编程-1相关推荐

  1. 【面向对象编程】(4) 类的继承,重构父类中的方法

    各位同学好,今天和大家分享一下面向对象编程中,类的三大特征之继承.主要介绍:子类继承父类的基本方法:重写父类的类方法:重构父类的初始化方法:super() 方法.本节主要是单继承,多继承在下一节中介绍 ...

  2. 【面向对象编程】(3) 类之间的交互,依赖关系,关联关系

    各位同学好,今天和大家分享一下面向对象编程中,类之间的交互,类之间的依赖关系和关联关系.有不明白的可见前一章节:https://blog.csdn.net/dgvv4/article/details/ ...

  3. 【面向对象编程】(1) 类实例化的基本方法

    各位同学好,本章节和大家分享一下面向对象编程的一些方法,通过一些案例带大家由浅入深掌握面向对象的编程. 1. 最基本的类实例化 创建类的方法是 class 变量名: ,实例化方法是 类名() ,分配属 ...

  4. C#编程概念系列(一):面向对象编程

    系列文章索引目录:http://www.cnblogs.com/loner/archive/2013/05/09/3068211.html 引子: 面向对象编程:这个在当下已不是什么时髦的概念,但通过 ...

  5. JavaScript面向对象编程

    自从有了Ajax这个概念,JavaScript作为Ajax的利器,其作用一路飙升.JavaScript最基本的使用,以及语法.浏览器对象等等东东在这里就不累赘了.把主要篇幅放在如何实现JavaScri ...

  6. python面向对象的优点_Python面向对象编程——总结面向对象的优点

    Python面向对象编程--总结面向对象的优点 一.从代码级别看面向对象 1.在没有学习类这个概念时,数据与功能是分离的 def exc1(host,port,db,charset): conn=co ...

  7. 转载知乎上的一篇:“ 面向对象编程的弊端是什么?”

    2019独角兽企业重金招聘Python工程师标准>>> 弊端是,没有人还记得面向对象原本要解决的问题是什么. 1.面向对象原本要解决什么(或者说有什么优良特性) 似乎很简单,但实际又 ...

  8. c语言面向对象编程中的类_C ++中的面向对象编程

    c语言面向对象编程中的类 Object oriented programming, OOP for short, aims to implement real world entities like ...

  9. ruby 新建对象_Ruby面向对象编程的简介

    ruby 新建对象 by Saul Costa 由Saul Costa Object-oriented programming (OOP) is a programming paradigm orga ...

  10. 面向对象编程概念_如何向6岁的孩子解释面向对象的编程概念

    面向对象编程概念 by Alexander Petkov 通过亚历山大·佩特科夫(Alexander Petkov) Have you noticed how the same cliche ques ...

最新文章

  1. 工业物联网将借助新兴技术实现华丽转身
  2. 李宏毅深度学习作业二
  3. 问题 | CSDN编辑图像怎么使图像居中、偏左、偏右
  4. 如何将rootfs打包进kernel image
  5. 作者:鲍玉斌(1968-),男,博士,东北大学计算机科学系教授
  6. 常用模块(json/pickle/shelve/XML)
  7. Linux/Documentations: Kernel Livepatching
  8. PHP 输入/输出流
  9. Linux常用命令--uname
  10. MySQL索引的使用及注意事项
  11. 170705、springboot编程之自定义properties
  12. 【高等数学】基本求导法则与导数公式
  13. 这届年轻人,为什么越挣钱越穷?
  14. LTE手机接收灵敏度究竟如何?
  15. ROS 学习踩坑笔记1-如何解决Roboware : Path is not ROS Workspace (Robo ware 无法打开workspace)
  16. Balsamiq 介绍
  17. 电子计算机发展经历几个阶段,计算机的发展经历几个阶段?每个阶段的电子原件及特征主要概述...
  18. IDEA警告: Redundant character escape xxx in RegExp
  19. 计算机学什专业,计算机专业到底学什么?
  20. 线性回归理解(附纯python实现)

热门文章

  1. docker中常用清理命令
  2. 小说分享《一个叫灾难的女孩》2
  3. 解读AI机器人养宠引领时尚潮流
  4. java随机生成名字,Java:随机生成不同的名称
  5. 恶意软件分析——RootKit高级分析技术
  6. VBA 连接Access数据库和Excle
  7. su oracle 和 su - oracle的区别
  8. 【BUUCTF】谁赢了比赛?
  9. ICLR 2023 | DIFFormer: 扩散过程启发的Transformer
  10. sfm是否可以实现二次元漫画风格