当前位置: 首页 > news >正文

汕头制作企业网站百度舆情监测平台

汕头制作企业网站,百度舆情监测平台,律师做网站推广有用吗,聊城网站建设企业6、方法 面向对象编程#xff08;OOP#xff09;#xff0c;封装、组合。 6.1 方法声明 在函数声明时#xff0c;在其名字之前放上一个变量#xff0c;即是一个方法。这个附加的参数会将该函数附加到这种类型上#xff0c;即相当于为这种类型定义了一个独占的方法。 …6、方法 面向对象编程OOP封装、组合。 6.1 方法声明 在函数声明时在其名字之前放上一个变量即是一个方法。这个附加的参数会将该函数附加到这种类型上即相当于为这种类型定义了一个独占的方法。 package geometryimport mathtype Point struct{ X, Y float64 }// traditional function func Distance(p, q Point) float64 {return math.Hypot(q.X-p.X, q.Y-p.Y) }// same thing, but as a method of the Point type func (p Point) Distance(q Point) float64 {return math.Hypot(q.X-p.X, q.Y-p.Y) }附加的参数p叫做方法的接收器(receiver)。 在方法调用过程中接收器参数一般会在方法名之前出现。这和方法声明是一样的都是接收器参数在方法名字之前。 p : Point{1, 2} q : Point{4, 6} fmt.Println(Distance(p, q)) // 5, function call fmt.Println(p.Distance(q)) // 5, method call第一个Distance的调用 实际上用的是包级别的函数geometry.Distance而第二个则是使用刚刚声明的Point调用的 是Point类下声明的Point.Distance方法。 这种p.Distance的表达式叫做选择器选择合适的对应p这个对象的Distance方法来执行。 选择器也会被用来选择一个struct类型的字段比如p.X。由于方法和字段都是在同一命名空间所以如果我们在这里声明一个X方法的话编译器会报错因为在调用p.X时会有歧义。 因为每种类型都有其方法的命名空间我们在用Distance这个名字的时候不同的Distance调 用指向了不同类型里的Distance方法。 // A Path is a journey connecting the points with straight lines. type Path []Point // Distance returns the distance traveled along the path. func (path Path) Distance() float64 {sum : 0.0for i : range path {if i 0 {sum path[i-1].Distance(path[i])} }return sum }我们可以给同一个包内的任意命名类型定义方法只要这个命名类型的底层类型(这个例子里底层类型是指[]Point这个slicePath就是命名类型)不是指针或者interface。 perim : Path{{1, 1},{5, 1},{5, 4},{1, 1}, } fmt.Println(perim.Distance()) // 12对于一个给定的类型其内部的方法都必须有唯一的方法名但是不同的类型却可以有同样的方法名。 方法比之函数的一些好处:方法名可以简短。 import gopl.io/ch6/geometry perim : geometry.Path{{1, 1}, {5, 1}, {5, 4}, {1, 1}} fmt.Println(geometry.PathDistance(perim)) // 12, standalone function fmt.Println(perim.Distance()) // 12, method of geometry.Path6.2 基于指针对象的方法 当这个接受者变量本身比较大时我们就可以用其指针而不是对象来声明方法。 func (p *Point) ScaleBy(factor float64) {p.X * factorp.Y * factor }方法的名字是 (*Point).ScaleBy。括号是必须的 为了避免歧义在声明方法时如果一个类型名本身是一个指针的话是不允许 其出现在接收器中的 type P *int func (P) f() { /* ... */ } // compile error: invalid receiver type想要调用指针类型方法 (*Point).ScaleBy 只要提供一个Point类型的指针即可 r : Point{1, 2} r.ScaleBy(2) fmt.Println(*r) // {2, 4}p : Point{1, 2} pptr : p pptr.ScaleBy(2) fmt.Println(p) // {2, 4}p : Point{1, 2} (p).ScaleBy(2) fmt.Println(p) // {2, 4}go如果接收器p是一个Point类型的变量并且其方法需要一个Point指针作为接收器我们可以用下面这种简短的写法: p.ScaleBy(2)编译器会隐式地帮我们用p去调用ScaleBy这个方法。这种简写方法只适用于“变量”我们不能通过一个无法取到地址的接收器来调用指针方法比如临时变量的内存地址就无法获取得到: Point{1, 2}.ScaleBy(2) // compile error: cant take address of Point literal我们可以用一个 *Point 这样的接收器来调用Point的方法因为我们可以通过地址来找到这个变量只要用解引用符号来取到该变量即可。 pptr.Distance(q) (*pptr).Distance(q)总结 不论是接收器的实际参数和其接收器的形式参数相同比如两者都是类型T或者都是类 型 *T : Point{1, 2}.Distance(q) // Point pptr.ScaleBy(2) // *Point接收器实参是类型T但接收器形参是类型 *T 这种情况下编译器会隐式地为我们取变量的地址: p.ScaleBy(2) // implicit (p)接收器实参是类型 *T 形参是类型T。编译器会隐式地为我们解引用取到指针指向的实际变量: pptr.Distance(q) // implicit (*pptr)6.2.1 Nil也是一个合法的接收器类型 package urltype Values map[string][]stringfunc (v Values) Get(key string) string{if vs:v[key];len(vs)0{return vs[0]}return }func (v Values) Add(key,value string){v[key]append(v[key],value) }m : url.Values{lang: {en}} // direct construction m.Add(item, 1) m.Add(item, 2) fmt.Println(m.Get(lang)) // en fmt.Println(m.Get(q)) // fmt.Println(m.Get(item)) // 1 (first value) fmt.Println(m[item]) // [1 2] (direct map access) m nil fmt.Println(m.Get(item)) // m.Add(item, 3) // panic: assignment to entry in nil mapnil的字面量编译器无法判断其准备类型。最后的那行m.Add的调用就会产生一 个panic因为他尝试更新一个空map。 6.3 通过嵌入结构体来扩展类型 import image/color type Point struct{ X, Y float64 } type ColoredPoint struct {PointColor color.RGBA }我们可以直接认为通过嵌入的字段就是 ColoredPoint自身的字段而完全不需要在调用时指出Point var cp ColoredPoint cp.X 1 fmt.Println(cp.Point.X) // 1 cp.Point.Y 2 fmt.Println(cp.Y) // 2可以把ColoredPoint类型当作接收器来调用 Point里的方法即使ColoredPoint里没有声明这些方法: red : color.RGBA{255, 0, 0, 255} blue : color.RGBA{0, 0, 255, 255} var p ColoredPoint{Point{1, 1}, red} var q ColoredPoint{Point{5, 4}, blue} fmt.Println(p.Distance(q.Point)) // 5 p.ScaleBy(2) q.ScaleBy(2) fmt.Println(p.Distance(q.Point)) // 10Point类的方法也被引入了ColoredPoint 尽管q有着Point这个内嵌类型我们也必须要显式地选择它。尝试直接传q的话你会看到下面这样的错误: p.Distance(q) // compile error: cannot use q (ColoredPoint) as Point一个ColoredPoint并不是一个Point但他has aPoint并且它有从Point类里引入的Distance 和ScaleBy方法。如果你喜欢从实现的角度来考虑问题内嵌字段会指导编译器去生成额外的包装方法来委托已经声明好的方法和下面的形式是等价的: func (p ColoredPoint) Distance(q Point) float64 {return p.Point.Distance(q) } func (p *ColoredPoint) ScaleBy(factor float64) {p.Point.ScaleBy(factor) }在类型中内嵌的匿名字段也可能是一个命名类型的指针这种情况下字段和方法会被间接地引入到当前的类型中(译注:访问需要通过该指针指向的对象去取)。添加这一层间接关系让我 们可以共享通用的结构并动态地改变对象之间的关系。下面这个ColoredPoint的声明内嵌了一 个*Point的指针。 type ColoredPoint struct {*PointColor color.RGBA } p : ColoredPoint{Point{1, 1}, red} q : ColoredPoint{Point{5, 4}, blue} fmt.Println(p.Distance(*q.Point)) // 5 q.Point p.Point // p and q now share the same Point p.ScaleBy(2) fmt.Println(*p.Point, *q.Point) // {2 2} {2 2}一个struct类型也可能会有多个匿名字段。我们将ColoredPoint定义为下面这样: type ColoredPoint struct {Pointcolor.RGBA }这种类型的值便会拥有Point和RGBA类型的所有方法以及直接定义在ColoredPoint中的方法。 var (mu sync.Mutex // guards mappingmapping make(map[string]string) ) func Lookup(key string) string {mu.Lock()v : mapping[key]mu.Unlock()return v }var cache struct {sync.Mutexmapping map[string]string }{mapping: make(map[string]string), }func Lookup(key string) string {cache.Lock()v : cache.mapping[key]cache.Unlock()return v }6.4 方法值和方法表达式 p : Point{1, 2} q : Point{4, 6} distanceFromP : p.Distance fmt.Println(distanceFromP(q)) var origin Point fmt.Println(distanceFromP(origin)) // 2.23606797749979, sqrt(5) scaleP : p.ScaleBy // method value scaleP(2) scaleP(3) scaleP(10) // p becomes (2, 4) // then (6, 12) // then (60, 120)time.AfterFunc这个函数的功能是 在指定的延迟时间之后来执行一个(译注:另外的)函数。且这个函数操作的是一个Rocket对象 r type Rocket struct { /* ... */ } func (r *Rocket) Launch() { /* ... */ } r : new(Rocket) time.AfterFunc(10 * time.Second, func() { r.Launch() })直接用方法值传入AfterFunc的话可以更为简短: time.AfterFunc(10 * time.Second, r.Launch)当调用一个方法时我们必须要用选择器(p.Distance)语法来指定方法的接收器。 当T是一个类型时方法表达式可能会写作 T.f 或者 (*T).f 会返回一个函数值这种函 数会将其第一个参数用作接收器所以可以用通常(译注:不写选择器)的方式来对其进行调用: p : Point{1, 2} q : Point{4, 6} distance : Point.Distance // method expression fmt.Println(distance(p, q)) // 5 fmt.Printf(%T\n, distance) // func(Point, Point) float64 scale : (*Point).ScaleBy scale(p, 2) fmt.Println(p) // {2 4} fmt.Printf(%T\n, scale) // func(*Point, float64) // 译注:这个Distance实际上是指定了Point对象为接收器的一个方法func (p Point) Distance() // 但通过Point.Distance得到的函数需要比实际的Distance方法多一个参数 // 即其需要用第一个额外参数指定接收器后面排列Distance方法的参数。 // 看起来本书中函数和方法的区别是指有没有接收器而不像其他语言那样是指有没有返回值。type Point struct{ X, Y float64 }func (p Point) Add(q Point) Point { return Point{p.X q.X, p.Y q.Y} } func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }type Path []Pointfunc (path Path) TranslateBy(offset Point, add bool) {var op func(p, q Point) Pointif add {op Point.Add} else {op Point.Sub}for i : range path {// Call either path[i].Add(offset) or path[i].Sub(offset).path[i] op(path[i], offset)} }6.5 封装 一个对象的变量或者方法如果对调用方是不可见的话一般就被定义为“封装”。封装有时候也 被叫做信息隐藏同时也是面向对象编程最关键的一个方面。 Go语言只有一种控制可见性的手段:大写首字母的标识符会从定义它们的包中被导出小写字母的则不会。这种限制包内成员的方式同样适用于struct或者一个类型的方法。因而如果我们想要封装一个对象我们必须将其定义为一个struct。 这也就是IntSet被定义为struct类型的原因尽管它只有一个字段: type IntSet struct {words []uint64 }一个struct类型的字段对同一个包的所有代码都有可见性无论你的代码是写在一个函数还是一个方法里。 封装的优点 因为调用方不能直接修改对象的变量值其只需要关注少量的语句并且只要弄懂少量变量的可能的值即可。隐藏实现的细节可以防止调用方依赖那些可能变化的具体实现这样使设计包的程序员在不破坏对外的api情况下能得到更大的自由。阻止了外部调用方对对象内部的值任意地进行修改。 下面的Counter类型允许调用方来增加counter变量的值并且允许将这个值reset为0但是不允许随便设置这个值 type Counter struct { n int } func (c *Counter) N() int { return c.n } func (c *Counter) Increment() { c.n } func (c *Counter) Reset() { c.n 0 }只用来访问或修改内部变量的函数被称为setter或者getter例子如下比如log包里的Logger 类型对应的一些函数。在命名一个getter方法时我们通常会省略掉前面的Get前缀。这种简洁上的偏好也可以推广到各种类型的前缀比如FetchFind或者Lookup。 package log type Logger struct {flags intprefix string// ... } func (l *Logger) Flags() int func (l *Logger) SetFlags(flag int) func (l *Logger) Prefix() string func (l *Logger) SetPrefix(prefix string)
http://www.pierceye.com/news/228245/

相关文章:

  • seo整站优化技术培训wordpress博客编辑器
  • 一家专做灯的网站招聘wordpress 欲思
  • 山西省建设主管部门网站app备案号查询平台官网
  • 百度网站收录链接提交做购物网站的开题报告
  • 迷你主机做网站服务器南京龙媒网络科技有限公司
  • 网站重构给一个网站如何做推广
  • 温州网站推广价钱左侧导航栏网站模板
  • 网站建设朝阳南昌房地产网站建设
  • 大连网络建站公司分析wordpress漫画主题推荐
  • 纪检监察网站建设 讲话制作书签的感受心得
  • 宁波网站建设公司优选亿企邦上海网站快速备案
  • 贵阳有做网站的公司吗微信营销软件免费版
  • 打开网站乱码怎么做河南平台网站建设
  • 物流网站源代码安平县网站建设
  • 自助服务器网站建设修改wordpress的库名
  • 惠州做网站乐云seo网站建设如何插音乐
  • 自媒体图片素材网站东莞网站建设推广技巧
  • 新浪网站是什么程序做的六安网站关键词排名优化地址
  • 手机网站大全123456镇江手机网站建设
  • 企业网站模板下载哪家公司强服装设计就业前景如何
  • 婚纱网站源代码网站制作专业的公司
  • 公司经营范围 网站开发网络工程好就业吗
  • 企业网站建设与管理试题wordpress设置页面访问权限
  • 中国顺德手机网站设计安居客做网站
  • 网站运营的含义百度地图轨迹导航
  • 网站开发时创业中文网站模板
  • 男人最爱的做网站网站建设合作合同范文
  • 我和你99谁做的网站做润滑油网站图片
  • 基于wordpress门户网站wordpress可以自己写代码吗
  • 自己做发卡网站wordpress搬家出问题