1.方法和函数的区别
(1).调用方式不一样
函数的调用方式: 函数名(实参列表)
方法的调用方式:变量.方法名(实参列表)
(2).对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
(3).对于方法(如struct的方法),接收者为值类型时,可以直接用指针类型的变变量调用方法,反过来同样也可以
package main
import(
"fmt"
)
type Person struct {
Name string
}
//函数
//对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
func test(p Person) {
fmt.Println(p.Name)
}
func test1(p *Person) {
fmt.Println(p.Name)
}
//对于方法(struct)
//接受者为值类型时,可以直接用指针类型的变量调用方法,反过来同样可以
func (p Person) test2(){
p.Name = "Jack"
fmt.Println("test2 = ", p.Name) // jack
}
func (p *Person) test3(){
p.Name = "Mary"
fmt.Println("test3 = ", p.Name) // Mary
}
func main() {
p := Person{"tom"}
test(p)//tom
test1(&p)//tom
p.test2()//tom
fmt.Println("main() p.Name =", p.Name) //tom
(&p).test2() //Jack,从形式上看是传入地址,但是本质仍然是值拷贝
fmt.Println("main() p.Name =", p.Name) //tom
(&p).test3()//Mary
fmt.Println("main() p.Name =", p.Name) //Mary
p.test3()//(&p).test3 等价p.test3 Mary;从形式上看是值,但是本质仍然是地址拷贝
fmt.Println("main() p.Name =", p.Name) //Mary
}
总结:
(1).不管调用形式如何,真正决定是值拷贝还是地址拷贝的,是要看这个方法是和哪个类型绑定
(2).如果是值类型,比如:(p Person)是值拷贝,如果是指针类型,比如:(p *Person)则是地址拷贝
2.面向对象编程应用实例
步骤:
(1).声明(定义)结构体,确定结构体名
(2).编写结构体的字段
(3).编写结构体的方法
案例1:
package main
import(
"fmt"
)
//1.编写一个Student结构体,包含name,gender,age,id,score字段,类型分别为:string,string,int,int,float64
//2.结构体中声明一个方法say,返回string类型,方法返回信息中包含所有字段值
//3.在main方法中,创建Student结构体实例(变量),并访问say,并将结果打印输出
type Student struct {
name string
gender string
age int
id int
score float64
}
func (stu *Student) say() string {
res := fmt.Sprintf("name=%v,gengder=%v,age=%v,id=%v,score=%v",
stu.name,stu.gender,stu.age,stu.id,stu.score)
return res
}
func main(){
stu := Student{
name:"张三",
gender:"男",
age:12,
id:1,
score:99.1,
}
result := stu.say()
fmt.Println(result)
}
案例2:
package main
import(
"fmt"
)
//景区门票案例
//一个景区根据游客的年龄收取不同的门票,年龄大于18小于60,20元,年龄小于18大于10,10,年龄小于10或者大于60,不让玩
//编写结构体Visitor,根据年龄判断门票价格并输出,当输入姓名为n时退出
type Visitor struct{
Name string
Age int
}
func (v *Visitor) ShowPrice() {
if v.Age < 10 || v.Age > 80 {
fmt.Println("考虑到安全,年龄应该在10~80之间")
return
}
if v.Age >= 18 && v.Age <= 60 {
fmt.Printf("姓名:%v票价为:20\n", v.Name)
} else if (v.Age < 18 && v.Age >= 10) || (v.Age > 60 && v.Age <= 80) {
fmt.Printf("姓名:%v票价为:10\n", v.Name)
}
}
func main(){
//定义一个结构体
var v Visitor
for {
fmt.Println("请输入姓名:")
fmt.Scanln(&v.Name)
if v.Name == "n" {
break
}
fmt.Println("请输入年龄:")
fmt.Scanln(&v.Age)
v.ShowPrice()
}
}
在创建结构体变量时,就直接给指定字段赋值
package main
import(
"fmt"
)
type Student struct{
Name string
Age int
}
func main(){
//方式一
//在创建结构体变量时,就直接给指定字段赋值
var stu = Student{"tom", 12} //stu ==> 结构体数据空间
stu1 := Student{"tom", 12}
fmt.Println(stu)//{tom 12}
fmt.Println(stu1)//{tom 12}
//在创建结构体变量时,把字段名和字段值写在一起,这种写法不依赖字段的定义顺序,更稳健
var stu3 = Student{
Age: 12,
Name: "tom",//顺序可以变化
}
stu4 := Student{
Name:"tom",
Age:12,
}
fmt.Println(stu3)//{tom 12}
fmt.Println(stu4)//{tom 12}
//方式二: 返回结构体的指针类型
var stu5 = &Student{"Jack", 14} //返回的是一个指针: stu5 ==> 地址 ===> 结构体数据空间[Name:xxx,Age:xxx]
//也可以这样
var stu5_1 *Student = &Student{"Jack", 14}
stu6 := &Student{"Jack", 14}
//在创建结构体指针变量时,把字段名和字段值写在一起,这种写法不依赖字段的定义顺序
var stu7 = &Student{
Name: "tom7",
Age: 12,
}
stu8 := &Student{
Name:"tom8",
Age:12,
}
fmt.Println(stu5)//&{Jack 14}
fmt.Println(stu5_1)//&{Jack 14}
fmt.Println(stu6)//&{Jack 14}
fmt.Println(stu7)//&{Jack 14}
fmt.Println(stu8)//&{Jack 14}
fmt.Println(*stu8)//{Jack 14}
}