Learn the Scala learning notes and exercise solutions (17-18 type parameters and advanced types)

Source: Internet
Author: User
Tags abstract aliases auth comparable getmessage ord square root traits

The version that Scala uses in this article is 2.11.8 17th, type parameter 17.1 generics

generic class

Class Pair[t, S] (Val first:t, Val second:s)

val p = new Pair ("String")
val p2 = new Pair[any, any ] ("String")

Generic Functions

def Getmiddle[t] (a:array[t]) = A (A.LENGTH/2)

Getmiddle (Array ("Mary", "had", "a", "little", "lamb"))

The following specific function is saved to f
val f = getmiddle[string] _
17.2 Definition

type variable definition

Upper bound (<:)

Class Pair[t <: Comparable[t]] (Val first:t, Val second:t) {
  def smaller = if (First.compareto (second) < 0) fi RST Else second

Nether (;:)

def Replacefirst[r;: T] (newfirst:r) = new Pair (Newfirst, second)

View definition (<%)

<% relationship means that T can be implicitly converted to Comparable[t]
class pair[t <% Comparable[t]]

Context Definition

The context is defined in the form of t:m, where M is another generic class. It requires that an "implicit value" of type m[t] must exist.

Class Pair[t:ordering] (Val first:t, Val second:t) {
    def smaller (implicit ord:ordering[t]) = 
        if (Ord.compare (fi RST, second) < 0) First else second

manifest Context Definition

Instantiating a generic array[t] with a base type requires a manifest[t] object.

def Makepair[t:manifest] (first:t, second:t) {
    val r = new Array[t] (2)
    r (0) = First
    R (1) = Second

Call Makepair (4, 9), the compiler will navigate to implicit manifest[int] and actually call Makepair (4, 9) (intmanifest), which returns an array of primitive types int[2].

Multiple Definitions

can have both upper and lower bounds, but not at the same time multiple upper bound or multiple nether
T;: Lower <: Upper

//can implement multiple traits
T <: comparable[t] with Serializable W ITH cloneable

//Multiple views define
T <% comparable[t] <% String

//multiple contexts defined
17.3 Type Constraints

A total of three relationships: T =:= u t <:< u t <%< u

These constraints will test whether T equals U, is a subtype of u, or can be converted to u by the view (implicit). You need to add an "implicit type proof parameter" when using:

Class Pair[t] (Val first:t, Val second:t) (Implicit ev:t <:< comparable[t])

define methods in a generic class that can be used only under certain conditions

Example one:

Class Pair[t] (Val first:t, Val second:t) {
    def smaller (implicit ev:t <:< ordered[t]) =
        if (First < SE COND) First else second

//Can construct pair[file], but only if the smaller method is called

Example two: The Ornull method of the option class

Val friends = Map ("Fred", "Barney", ...)
Val friendopt = Friends.get ("Wilma")//option[string]
val friendornull = friendopt.ornull//either String or null

For value types, you can still instantiate Option[int], as long as you don't use Ornull.

Improved type inference

def Firstlast[a, C <: Iterable[a]] (IT:C) = (It.head, it.last)

//When the following code is executed: Firstlast (List (1, 2, 3)), the non-expected type is inferred [not Hing, List[int]
//Because it is a and C matching the same step, to solve this problem, you must first match C, then match A:
def Firstlast[a, C] (IT:C) (Implicit ev:c <:< Iterable[a]) = (It.head, it.last)
17.4 Type Change

co-change: C[+t]

If a is a subclass of B, then C[a] is a subclass of C[b].

Class Pair[+t] (Val first:t, Val second:t)

The + sign means that the type is covariant with T, that is, it changes in the same direction as T. Because Student is a subtype of person, Pair[student] is also a subtype of Pair[person].

inversion: c[-t]

If a is a subclass of B, then C[a] is the parent class of c[b].

Trait Friend[-t] {
    def befriend (someone:t)

def makefriendwith (S:student, f:friend[student]) { F.befriend (s)}

//Under Relationship
class Person extends Friend[person]
class Student extends person
val Susan = new S Tudent
val fred = new Person

//can use the following call, output student result, can be put into Array[person]
Makefriendwith (Susan, Fred)
17.5 covariant and contravariant points
Class Pair[+t] (Var first:t, var second:t)

Will error, said in the following setter method, the covariant type T appears in the inversion point: first_= (value:t)

The parameter position is the contravariant point, and the position of the return type is the covariant point.

In the function parameter, the type change is reversed, and the parameter is covariant. For example (Iterable[+a] of the Foldleft method):

FOLDLEFT[B] (Z:B) (OP: (b, A) = b): b
               -       +  +     -   +

A is now at the covariant point.

Consider the Replacefirst method of the following immutable duality:

Class Pair[+t] (Val first:t, Val second:t) {
    def replacefirst (newfirst:t) = new Pair[t] (Newfirst, second)

The compiler will give an error because type T appears on the contravariant point, and the workaround is to add another type parameter to the method:

Class Pair[+t] (Val first:t, Val second:t) {
    def replacefirst[r;: T] (newfirst:r) = new Pair[r] (Newfirst, second)
17.6 object cannot be generic

You cannot add a type parameter to an object. For example:

Abstract class List[+t] {
    def isempty:boolean
    def head:t
    def Tail:list[t]

class Node[t] (Val head : T, Val tail:list[t]) extends List[t] {
    def isEmpty = False

object Empty[t] extends List[t]//Error

Workaround One:
class Empty[t] extends List[t] {
    def IsEmpty = True
    def head = throw new Unsupportedoperationexce Ption
    def tail = throw new Unsupportedoperationexception

//Solution Two:
object Empty extends list[ Nothing]
//According to covariant rules, list[nothing] can be converted to List[int]
17.7 type wildcard characters

_ is a wildcard used in Scala.

def process (people:java.util.list[_ <: person]

import java.util.Comparator
def Min[t] ( P:pair[t]) (comp:comparator[_;: T])
17.8 Problem Solving

1. Define an immutable class Pair[t,s], with a swap method, to return the new duality of the component swap position.

2. Define a mutable class Pair[t], with a swap method, to swap the position of the components in the dual.

3. Given class Pair[t, S], write a generic method swap, accept the dual as a parameter and return the new duality of the component's swapped position.

4. In section 17.3, if we want to replace the first component of Pair[person] with student, why do we not need to set a lower bound to the Replacefirst method?

5. Why Richint achieve Comparable[int] instead of Comparable[richint]?

6. Write a generic method middle that returns the intermediate elements of any iterable[t]. For example, Middle ("world") should get ' R '.

7. View Iterable[+a] traits. Which methods used the type parameter a. Why in these methods the type parameter is in the covariant point.

8. In section 17.10, the Replacefirst method has a type definition. Why you cannot define an equivalent method on a mutable pair[t].

def Replacefirst[r;: T] (newfirst:r) {first = Newfirst}//Error

9. Restricting method parameters in an immutable class pair[+t] may seem strange. However, let's assume you can define it in pair[+t]

def replacefirst (Newfirst:t)

The problem is that the method may be rewritten (in some unreliable way). Constructs an example of this. Define a pair[double] type Nastydoublepair, override the Replacefirst method, and use the square root of the Newfirst to do the new duality. Replacefirst ("Hello") is then called for Pair[any] with the actual type Nastydoublepair.

10. Given a mutable class pair[s,t], use a type constraint to define a swap method that can be called when the type parameter is the same.
18th Chapter Advanced Type 18.1 Single Case type

Subclass Example

Class Document {
    def settitle (title:string): This.type = {..., this}
    def setauthor (author:string) = {..., thi s}

Class Book extends Document {
    def addchapter (chapter:string) = {...

Notice the scarlet Letter above so that you can make the following call:

Val book = new book ()
book.settitle ("Scala for the Impatient"). Addchapter (Chapter1)

Object Example

Object Title

class Document {
    private var usenextargas:any = null
    def set (obj:Title.type): This.type = {Use Nextargas = obj; This}

Note that the above Scarlet letter, if used obj:title, refers to a singleton object instead of a type. 18.2 Type projection

The nested class is subordinate to its external object, as follows:

Import Scala.collection.mutable.ArrayBuffer

class Network {
    class Member (Val name:string) {
        val contacts = new Arraybuffer[member]

    private val members = new Arraybuffer[member]

    def join (name:string) = {
        val m = new Member (name) members
        + =

This allows each network instance to have its own member class.

If you do not want to use "each object's own inner class" in all places, you can use the type projection network#member meaning is any network member.

Class Network {
    class Member (Val name:string) {
        val contacts = new Arraybuffer[network#member]
18.3 Path

An expression such as com.demo.chatterobj.Member is called a path. And before the final type, all components of the path must be "stable," i.e. it must be specified to a single, poor range, which must be one of the following: Package object Val This, super, Super[s], c.this, C.super, or C.super[s] 18.4 Type aliases

You can create a simple alias with the Type keyword:

Class Book {
    import scala.collection.mutable._
    type Index = hashmap[string, (int, int)]

You can then use Book.index instead of scala.collection.mutable.hashmap[string, (int, int)].

In addition, type aliases must be nested within a class or object, and it cannot appear at the top level of the Scala file. 18.5 Structure Type

Refers to a set of specifications for abstract methods, fields, and types. For example:

def appendlines (target: {def append (str:string): any}, lines:iterable[string]) {
18.6 Composite Types

The defined form is as follows:

T1 with T2 with T3 ...

Among them, T1, T2, T3, etc. are the types. To be an instance of this composite type, a value must meet the requirements of each type. That is, such a type is also called the intersection type.

For example:

Val image = new arraybuffer[java.awt.shape with java.io.Serializable]
//can only add those immediate shape (shape) is also an object that can be serialized.

val rect = new Rectangle (5, ten, +),
image + = rect//Ok,rectangle is Serializable's
image + = new Area (rect)/ /error, area is shape but not serializable
18.7 Middle-mounted type

A type with two type parameters, denoted by the middle syntax, and the type name is written between two type parameters, for example

String Map int

//instead of
map[string, int]

In Scala, you can define:

Type x[a, b] = (A, b)

//after which you can write
a string x int
//instead of
(string, int)

In addition, the middle-type operators have the same precedence and are left-associative. That

string x int x int
((String, int), int)
18.8 Existence Type

The way to define this is to follow the forsome {...} after the type expression, with the declaration of type and Val included in the curly braces.

Array[t] Forsome {type T <: jcomponent}

Scala's type wildcard is simply the existence of a type of "syntactic sugar", such as:

Map[_, _]
//equal to
map[t, U] forsome {type T; Type U}

Only Forsome can use more complex relationships:

def process[m <: N.member forsome {val n:network}] (m1:m, m2:m) = (m1, m2)

//The method will accept members of the same network, but deny members from different networks 
   val chatter = new network
val myface = new network
val fred = Chatter.join ("Fred")
val wilma = Chatter.join (" Wilma ")
val Barney = Myface.join (" Barney ")
process (Fred, Wilma)//OK
process (Fred, Barney)//Error
18.9 Scala type system
type Grammar Description
class or trait Class C ..., trait C ... 5th, 10 chapters
Meta-group (T1, ..., Tn) Section 4.7
function type (T1, ..., Tn) = = T
Types with annotations T@a 15th Chapter
parameterized types A[t1, ..., Tn] 17th Chapter
Single Case Type Value. Type 18th Chapter
Type projection O#i 18th Chapter
Composite type T1 with T2 ... with Tn {declaration} 18th Chapter
Middle Type T1 A T2 18th Chapter
Existence type T forsome {type and Val declaration} 18th Chapter
18.10 type of self

The declaration of its own type (self type) defines the trait: this: type =>, such a trait can only be mixed into subclasses of a given type.

Trait logged {
    def log (msg:string)

trait Loggedexception extends logged {
    this:exception =
      def log () {log (GetMessage ())}
      //Can call GetMessage because this is a exception
Val f = new JFrame with loggedexception
//Error: JFrame is not a subtype of Loggedexception's own type exception

When multiple types are required, a composite type can be used:

This:t with U ... =
18.11 Dependency Injection

In Scala, it is possible to achieve a simple dependency injection effect by nature and by its own type. For example log function:

Trait Logger {def log (msg:string)}

//Has two implementations of this trait, Consolelogger and FileLogger.

//user authentication trait there is a dependency on log function to record authentication failure:
trait Auth {
    This:logger =
        def login (id:string, password:string) : Boolean

//Application logic depends on these two traits:
trait app {
    This:logger with Auth ...

Then, you can assemble our application like this:
object MyApp extends app with FileLogger ("Test.log") with Mockauth ("Users.txt")

The cake pattern gives a better design, in which a component trait is provided for each service, which includes: any dependent component that describes the attributes of the service interface in its own type an abstract Val, which will be initialized to an instance of the service can optionally contain the implementation of the Service interface

Trait loggercomponent {
    trait Logger {...}
    Val Logger:logger
    class FileLogger (file:string) extends Logger {...}

Trait Authcomponent {
    this:loggercomponent =//Allow us to access the logger

    trait Auth {...}
    Val Auth:auth
    class Mockauth (file:string) extends Auth {...}

The component configuration
object Appcomponents extends loggercomponent with authcomponent {
    val logger = new FileLogger ("Test.log ")
    val auth = new Mockauth (" Users.txt ")
18.12 Abstract Types

A class or trait can define an abstract type that is materialized in a subclass. For example:

Trait Reader {
  type Contents
  def read (filename:string): Contents

//Here, type Contents is abstract, The specific subclass needs to specify this type:
class StringReader extends Reader {
  type Contents = String
  def read (filename:string) = Source . FromFile (FileName, "UTF-8"). Mkstring

class ImageReader extends Reader {
  type Contents = bufferedimage< C10/>def Read (filename:string) = Imageio.read (new File)

The same effect can also be achieved by type parameters:

Trait Reader[c] {
  def read (filename:string): C

class StringReader extends Reader[string] {
  def Read (filename:string) = Source.fromfile (FileName, "UTF-8"). Mkstring

class ImageReader extends reader[ BufferedImage] {
  def read (filename:string) = Imageio.read (new File)

Scala's rule of thumb is that if the type is given when the class is instantiated, the type argument is used if the type is given in the subclass, the abstract type

Abstract types are easier to use when there are multiple types of dependencies--Avoid using a long string of type parameters:

Trait Reader {
  type in
  type Contents
  def read (in:in): Contents

class ImageReader extends Reader { C5/>type in = File
  type Contents = BufferedImage
  def read (file:in) = imageio.read (file)

Abstract types can have type definitions

Trait Listener {
  type Event <: Java.util.EventObject

Subclasses must provide a compatible type
trait ActionListener extends Listener {
  type Event = java.awt.event.ActionEvent  //OK, This is a sub-type
18.13 Family Polymorphism

Take the example of client-side Java event handling:

generic type Example

Trait Listener[e] {def occurred (e:e): Unit}//Event source requires a collection of listeners, and a method to trigger these listeners trait source[e, L <: Listener[e]] { Private Val listeners = new Arraybuffer[l] def add (l:l) {listeners + = L} def remove (l:l) {listeners = L } def Fire (e:e) {for (L <-listeners) l.occurred (e)}}//Button trigger action event, listener type trait ActionListener exten DS Listener[actionevent]//Button class mixed with Source Trait class button extends Source[actionevent, ActionListener] {def click ()

{Fire (new ActionEvent (This, actionevent.action_performed, "click")}}} The ActionEvent class sets the event source to this, but the event source is of type object.  You can use your own type to make it also type safe: trait Event[s] {var source:s = _} trait Listener[s, E <: Event[s]] {def occurred (e:e): Unit} trait Source[s, E <: Event[s], L <: Listener[s, E]] {this:s = private val listeners = new
           ARRAYBUFFER[L] def Add (l:l) {listeners + = l} def remove (l:l) {listeners-L} def Fire (e:e) { E.sourCE = this//requires itself type for (l <-listeners) l.occurred (e)}}//define button 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.