Beginning Scala study note(7) Trait
A trait provides code reusability in Scala by encapsulating method and state and then offing possibility of mixing them into classes thus allowing code reuse.
#define Trait Gliding
scala> trait Gliding{
| def gliding(){ println("gliding")}
| }
defined trait Gliding
Gliding does not declare a superclass, so like a class, it has the default superclass of AnyRef. It defines one concrete method.
1. Using Traits as Mixins
You can create a trait that inherits from a Class, as well as a Class that extends a trait. Once a trait is defined, it can be mixed in to a class using either the extends or with keywords.
# Mixin by extending the trait
scala> class Glider extends Gliding{
| override def toString = "glider"
| }
defined class Glider
scala> val glider = new Glider
glider: Glider = glider
scala> glider.gliding
gliding
A trait also defines a type.
scala> val g: Gliding = glider
g: Gliding = glider
scala> g.gliding
gliding # override the trait's method
scala> class Glider extends Gliding{
| override def toString = "glider"
| override def gliding(){
| println("race for now "+ toString)
| }
| }
defined class Glider
scala> val glider = new Glider
glider: Glider = glider
scala> glider.gliding
race for now glider # declaring methods in a trait
scala> trait TraitA{
| def methodA
| def methodAWithParam(param: String)
| def methodWithReturnType: String
| }
defined trait TraitA # trait extending another trait
scala> trait TraitB extends TraitA{
| def methodB
| }
defined trait TraitB
When a class extends a trait, it use the extends and with keywords based on whether the class extends one trait or several traits.
# extending one trait
scala> class ClassA extends TraitA{}
# extending multiple traits
class ClassA extends TraitA with TraitB{}
# extending class and traits
class ClassA extends ClassB with TraitA with TraitB{}
A class extending the trait must implement all the abstract methods of trait, unless the class extending a trait is itself abstract.
# concrete class must implement all abstract methods of trait
scala> class ClassA extends TraitA{
| def methodA {}
| def methodWithParam(param: String){}
| def methodWithReturnType: String{}
| }
Note that a trait can be comprised of both abstract and concrete methods. If a class extends a trait but does not implement the abstract methods defined in the trait, the class extending the trait must be declared abstract.
# extending class not implementing abstract methods of trait must be abstract
scala> abstract class ClassA extends TraitA{
| def methodA {}
| def methodWithParam(param: String){}
| }
defined class ClassA # trait with implementation
scala> trait Vehicle{
| def drive{println("Driving")}
| def race
| }
defined trait Vehicle
# subclass does not override the trait's drive method
scala> class car extends Vehicle{
| def race {("Racing the car")}
| }
defined class car
# subclass overrides the trait drive method
scala> class boat extends Vehicle{
| override def drive{("float")}
| def race{("Racing boat")}
| }
defined class boat
Although Scala has abstract classes, it's recommended to use traits instead of abstract classes to implement base behavior because a class can extend only one abstract class, but it can implement multiple traits. If you want the base behavior to be inherited in Java code, use an abstract class.
# trait with abstract and concrete fields
scala> trait CarTrait{
| var door: Int
| var seat =
| }
defined trait CarTrait
# override keyword not necessary for var field
scala> class Car extends CarTrait{
| var door =
| seat =
| }
defined class Car
You need to use the override keyword in a subclass of a trait to override a val field.
# override keyword necessary for val field
scala> trait CarTrait{
| val door: Int
| }
defined trait CarTrait
scala> class Car extends CarTrait{
| override val door =
| }
defined class Car
A class definition can have the parameters passed to the primary constructor of a class but a trait definition cannot have such parameters.
2. Trait and Class Hierarchies
Traits also can have rules about what kind of classes and other traits they can be mixed into. Further, you can declare method parameters that are a consolidation of types.
# only instances of classes that extends Baz, Blarg, and FruitBat may be passed into this method
def foo(bar: Baz with Blarg with FruitBat)
事例:
# modelling living things
abstract class LivingThing
abstract class Plant extends LivingThing
abstract class Animal extends LivingThing # trait HasLegs
trait HasLegs extends Animal{
def walk(){println("Walking")}
}
A trait extending a class means that the compiler will only let you mix HasLegs into something that subclasses from Animals.
# trait HasWings
trait HasWings extends Animal{
def flap(){println("Flap Flap")}
}
We define the rules of the self type with "this: HasWings =>". The compiler flags an error if this trait is not mixed into a class that also extends HasWings.
trait Flies{
this: HasWings =>
def fly(){println("I'm flying")}
} abstract class Bird extends Animal with HasWings with HasLegs # concrete Birds
class Robin extends Bird with Flies
class Ostrich extends Bird # mammal behavior
abstract class Mammal extends Animal{
def bodyTemperature: Double
} # KnowsName Trait
trait KnowsName extends Animal{
def name: String
} # Dog has legs knows its name
class Dog(val name: String) extends Mammal with HasLegs with KnowsName{
def bodyTemperature: Double = 99.3
} # Ignores Names Trait
trait IgnoresName{
this: KnowsName =>
def ignoreName(when: String): Boolean def currentName(when: String): Option[String] =
if (ignoreName(when)) None else Some(name)
} # Cat Ignores Name except at dinner time
class Cat(val name: String) extends Mammal with HasLegs with KnowsName with IgnoresName{
def ignoreName(when: String) = when match{
case "Dinner" => false
case _ => true
}
def bodyTemperature: Double = 99.5
} trait Athlete extends Animal # Runner Trait
trait Runner{
this: Athlete with HasLegs =>
def run(){println("I'm running")}
} # Person is mammal with legs and knows its name
class Person(val name: String) extends Mammal with HasLegs with KnowsName{
def bodyTemperature: Double = 98.6
} # Biker Trait
trait Biker extends Person{
this: Athlete =>
def ride(){println("I'm riding my bike")}
} # define Gender
trait Gender
trait Male extends Gender
trait Female extends Gender # the compiler enforced our rule about Bikers needing to be Persons.
scala> val bikerDog = new Dog("biker") with Athlete wit Biker
<console>:: error: value wit is not a member of Dog with Athlete
val bikerDog = new Dog("biker") with Athlete wit Biker
^
Please note that we can combine different traits as part of the object creation.
scala> val archer = new Dog("archer") with Athlete with Runner with Male
archer: Dog with Athlete with Runner with Male = $anon$@6106258e scala> val dpp = new Person("David") with Athlete with Biker with Male
dpp: Person with Athlete with Biker with Male = $anon$@6a0147e1 scala> val john = new Person("John") with Athlete with Runner with Male
john: Person with Athlete with Runner with Male = $anon$@5c97a513 scala> val annette = new Person("Annette") with Athlete with Runner with Female
annette: Person with Athlete with Runner with Female = $anon$@3c42eee3 scala> def goBiking(b: Biker) = println(b.name + " is biking")
goBiking: (b: Biker)Unit scala> goBiking(dpp)
David is biking # The method requires a Biker, and Annette is not a Biker.
scala> goBiking(annette)
<console>:: error: type mismatch;
found : Person with Athlete with Runner with Female
required: Biker
goBiking(annette)
^
However, just as we can compose a class out of traits, we can require that a class implement more than one trait in order to be the parameter to a method:
scala> def charityRun(r: Person with Runner) = r.run()
charityRun: (r: Person with Runner)Unit scala> charityRun(john)
I'm running
scala> charityRun(archer)
<console>:: error: type mismatch;
found : archer.type (with underlying type Dog with Athlete with Runner with Male)
required: Person with Runner
charityRun(archer)
^
# only be called with a parameter that's both a Runner and a Female:
scala> def womensRun(r: Runner with Female) = r.run()
womensRun: (r: Runner with Female)Unit
scala> womensRun(annette)
I'm running
scala> val madeline = new Cat("Madeline") with Athlete with Runner with Female
madeline: Cat with Athlete with Runner with Female = $anon$@38d5857c
scala> womensRun(madeline)
I'm running
Scala's compositional rules are very powerful tools for defining complex class hierarchies and for specifying the rules for composing classes as well as the rules for passing parameters into methods.
Beginning Scala study note(7) Trait的更多相关文章
- Beginning Scala study note(9) Scala and Java Interoperability
1. Translating Java Classes to Scala Classes Example 1: # a class declaration in Java public class B ...
- Beginning Scala study note(3) Object Orientation in Scala
1. The three principles of OOP are encapsulation(封装性), inheritance(继承性) and polymorphism(多态性). examp ...
- Beginning Scala study note(2) Basics of Scala
1. Variables (1) Three ways to define variables: 1) val refers to define an immutable variable; scal ...
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
- Beginning Scala study note(8) Scala Type System
1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the h ...
- Beginning Scala study note(6) Scala Collections
Scala's object-oriented collections support mutable and immutable type hierarchies. Also support fun ...
- Beginning Scala study note(5) Pattern Matching
The basic functional cornerstones of Scala: immutable data types, passing of functions as parameters ...
- Beginning Scala study note(1) Geting Started with Scala
1. Scala is a contraction of "scalable" and "language". It's a fusion of objecte ...
- Scala学习笔记--特质trait
http://outofmemory.cn/scala/scala-trait-introduce-and-example 与Java相似之处 Scala类型系统的基础部分是与Java非常相像的.Sc ...
随机推荐
- Excel—分离中英文字符
1.如下图: 2.提取中文字符为: 3.提取应为字符为: 4.说明: 该方法的原理利用了LENB和LEN计算方法的不同,LEN计算字符数,中英文都算作一个字符:LENB计算字节数,中文算两个字节,英文 ...
- nyoj 473 A^B Problem
A^B Problem 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 Give you two numbers a and b,how to know the a^ ...
- 谈谈__proto__和prototype的区别
我想javascript中的原型链一直想很多初学javascript的同学感到非常的困惑,今天看了一些文章,结合自己的理解,把原型链这个东西从新来整理一下,如有不对之处,望大家帮忙指出. 首先,我们应 ...
- dom解析和sax解析的区别及优缺点
dom解析一开始就将文档所有内容装入内存,每个元素(标签)都作为一个element对象存储,形成对象树,缺点是对内存占用大,不能解析数据量很大的文档:优点是方便进行crud操作. sax解析,逐行解析 ...
- PHP延迟静态绑定
类可以自下往上调用父类方法,如果需要在父类中根据不同的子类,来调用子类的方法,那么就需要延迟静态绑定.延迟静态绑定用的是保留关键词static. 所谓延迟静态绑定,顾名思义,静态调用时::符号左侧的部 ...
- Open Xml 读取Excel中的图片
在我的一个项目中,需要分析客户提供的Excel, 读出其中的图片信息(显示在Excel的第几行,第几列,以及图片本身). 网络上有许多使用Open Xml插入图片到Word,Excel的文章, 但 ...
- Angularjs2 入门
1.创建文件夹 mkdir angular2-app cd angular2-app 2.配置Typescript 需要通过一些特殊的设置来指导Typesript进行编译.新建一个 tsconfig. ...
- 【Android自学日记】五大布局常用属性
线性布局(LinearLayout)常用属性: android:orientation="vertical"--决定子类控件的排布方式(vertical垂直:horizontal水 ...
- php加密类
1.需求 了解php加密类的使用 2.例子 参考ci的3.1.2的新版加密类,一个不传参,用默认加密算法,加密模式的例子 //0.加载加密类 $this->load->library('e ...
- C#高级编程笔记2016年10月12日 运算符重载
1.运算符重载:运算符重重载的关键是在对象上不能总是只调用方法或属性,有时还需要做一些其他工作,例如,对数值进行相加.相乘或逻辑操作等.例如,语句if(a==b).对于类,这个语句在默认状态下会比较引 ...