Created
March 28, 2012 15:31
-
-
Save halfninja/2227348 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* A selection of illustrative lines that describe a bit about how Scala does things | |
* and various parts of the language and/or library that you might find useful often. | |
*/ | |
// val is similar to a final variable in Java - it can't be reassigned | |
val filename = "log.txt" | |
// var can be changed | |
var filename = "log.txt" | |
// type can be inferred, or you can be explicit | |
var filename:String = "log.txt" | |
// various collection types | |
val numbers = Seq(1,2,3) | |
val names = List("Ed","Fred") | |
// anonymous functions can be passed to methods, e.g. the map method | |
names.map(v => v.toUpperCase()) | |
// returns List("ED","FRED"). A shorter version, where _ is a magic placeholder symbol | |
names.map(_.toUpperCase) | |
// also omitted the empty parens at the end, they're optional. | |
// parens and braces are usually interchangable too | |
// It's usually possible to omit even the dot before a method, which | |
// allows cool things like | |
val vegetables = Seq("Lettuce","Tomato") | |
val dressing = Seq("Vinegar","Oil") | |
val salad = vegetables ++ dressing | |
// What's happening on the last line is actually a method called "++", defined on most collections: | |
val salad = vegetables.++(dressing) | |
/** CLASSES */ | |
// Class with constructor. If you don't have methods, you can leave out the body | |
class Dog(name:String) | |
// Make the name property readable | |
class Dog(val name:String) | |
// Extend a superclass and call its super-constructor | |
class Animal(legs:Int) | |
class Dog(val name:String) extends Animal(4) | |
// Let's add some methods. Fairly recognisable syntax. | |
// You can often omit things like brackets and braces for brevity. | |
class Dog(val name:String) { | |
def greet(yourName:String) { | |
val message = "Hello %s! My name is %s." format (yourName, name) | |
println(message) | |
} | |
def bark = println("woof!") | |
} | |
new Dog("Rex").greet("Ron") | |
// Hello Ron! My name is Rex. | |
/** OBJECTS */ | |
// objects are a bit like singleton classes. | |
object Methods { | |
val get = "GET" | |
val put = "PUT" | |
// If you have an "apply" method on an object, you can call it like it's a method. | |
def apply() = new Dog("HTTP") | |
} | |
val webdog = Methods() // weird example | |
/** Pattern matching */ | |
// Actually unrelated to regex (though regex is one thing it can be used for), | |
// it actually matches objects. | |
val fileDescription = myPage match { | |
case p:HtmlPage => "This is an HTML page" | |
case p:BinaryPage => "This is a file" | |
case _ => "Nobody knows what this is" | |
} | |
// some classes can be used to match inputs - it's a bit complicated to make your | |
// own but the Regex class is a good example of one that uses this technique | |
val NamePattern = """(\w+) (\w+)""".r // the r method makes a regex from a string | |
"Ronald Reagan" match { | |
case NamePattern(first, last) => println("Hello, "+first+"!") | |
case _ => println("Your name did not match my incredibly strict rules.") | |
} | |
/** JAVA INTEROP */ | |
// Stuff mostly just works, but a few things you'll need. | |
// This import adds implicit conversions between Scala and Java collections | |
import collection.JavaConversions._ | |
val myjavalist:java.util.List[String] = Seq("This","Gets","Converted") | |
// gets converted back on demand if you want to use Scala-style methods on your Java list | |
myjavalist.filter{_.length == 4} | |
// -> just the items with length == 4 | |
// JavaBeans | |
// only really an issue if you use something like Spring that lives and breathes | |
// JavaBeans getters and setters. | |
// You could define the methods yourself, or you can use the handy @BeanProperty annotation: | |
@BeanProperty var name:String = _ // _ is a placeholder for the default value, in this case null. | |
/** THE OPTION CLASS */ | |
// This isn't any special language feature, it's just a library class, | |
// but it makes use of some Scala features. | |
// It's intended to be a replacement for null values. Option[T] is a type which can either be | |
// Some(value) or None. It makes dealing with empty values easier. | |
// It helps to think of it as a sort of collection that contains either zero or one things. It even | |
// has a bunch of methods that are similar to the collection methods, like map(). | |
// Using map(), you can grab properties out of it without worrying whether it's actually None - | |
// if it's None, it returns None. | |
val dog: Option[Dog] = findDogById(97) | |
val dogName = dog.map(_.name) | |
println(dogName.getOrElse("Nameless Dog")) | |
// It doesn't make null pointer exceptions impossible, it just makes them less likely, | |
// and makes code that's a bit easier to read than a brazillion "(if x != null)" statements. | |
// You can use the Option() method to wrap a regular variable - null becomes None. | |
Option(maybeNullDog) map { _.name } getOrElse ( "Anonydog" ) | |
/** IMPLICIT */ | |
// The "implicit" keyword can be used in a few places. The coolest place is on a method. | |
class AddNineable(num:Int) { | |
def addNine = num + 9 | |
} | |
implicit def ToAddNineable(num:Int) = new AddNineable(num) | |
3.addNine // -> 12 | |
// as you can see, the implicit conversion effectively allows you to mix in new methods to | |
// existing classes, by implicitly wrapping them in an adapter class. This is how the | |
// JavaConversions methods work. | |
// the other place you can use implicits is on variables and argument lists. | |
// Unless it makes the code hugely easier to use, it's best not to use it yourself | |
// as it can be confusing to have object magically passed in to methods. | |
// confusing example here: http://www.scala-lang.org/node/114 | |
/** MANIFESTS */ | |
// Manifests are a workaround for a limitation with the JVM. If you use generic types, the actual type | |
// is only available at compile time, and lost at runtime. | |
// This won't work: | |
def doesItHaveType[T](obj:Object) = obj instanceof T | |
// You can't do it in the JVM because it doesn't know what T is when you call it. Manifests are a class | |
// that Scala can implicitly provide to the method, containing information about T. | |
def doesItHaveType[T](obj:Object)(implicit manifest:Manifest[T]) = manifest.erasure.isInstance(obj) | |
// We've introduced two other Scala features here: implicit arguments, and multiple parameter lists. | |
// The second parameter list is implicit so its arguments are discovered by the compiler, and added. | |
// You can then call it like | |
val isString = doesItHaveType[String](myObject) | |
// This example is silly because we already have myObject.isInstance[String], but it illustrates the feature. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment