Going back to this example from the previous section:
val doubledInts = ints.map((i: Int) => i * 2)
We noted that this part of the expression is an anonymous function:
(i: Int) => i * 2
The reason it’s called anonymous is because it’s not assigned to a variable, and therefore doesn’t have a name.
However, an anonymous function—also known as a function literal—can be assigned to a variable to create a function variable:
val double = (i: Int) => i * 2
This creates a function variable named double
.
In this expression, the original function literal is on the right side of the =
symbol:
val double = (i: Int) => i * 2
-----------------
the new variable name is on the left side:
val double = (i: Int) => i * 2
------
and the function’s parameter list is underlined here:
val double = (i: Int) => i * 2
--------
Like the parameter list for a method, this means that the double
function takes one parameter, an Int
named i
.
You can see in the REPL that double
has the type Int => Int
, meaning that it takes a single Int
parameter and returns an Int
:
scala> val double = (i: Int) => i * 2
val double: Int => Int = ...
Invoking the function
Now you can call the double
function like this:
val x = double(2) // 4
You can also pass double
into a map
call:
List(1, 2, 3).map(double) // List(2, 4, 6)
Furthermore, when you have other functions of the Int => Int
type:
val triple = (i: Int) => i * 3
you can store them in a List
or Map
:
val functionList = List(double, triple)
val functionMap = Map(
"2x" -> double,
"3x" -> triple
)
If you paste those expressions into the REPL, you’ll see that they have these types:
// a List that contains functions of the type `Int => Int`
functionList: List[Int => Int]
// a Map whose keys have the type `String`, and whose
// values have the type `Int => Int`
functionMap: Map[String, Int => Int]
Key points
The important parts here are:
- To create a function variable, just assign a variable name to a function literal
- Once you have a function, you can treat it like any other variable, i.e., like a
String
orInt
variable
And thanks to the improved Eta Expansion functionality in Scala 3, you can treat methods in the same way.
Contributors to this page:
Contents
- Introduction
- Scala Features
- Why Scala 3?
- A Taste of Scala
- Hello, World!
- The REPL
- Variables and Data Types
- Control Structures
- Domain Modeling
- Methods
- First-Class Functions
- Singleton Objects
- Collections
- Contextual Abstractions
- Toplevel Definitions
- Summary
- A First Look at Types
- String Interpolation
- Control Structures
- Domain Modeling
- Tools
- OOP Modeling
- FP Modeling
- Methods
- Method Features
- Main Methods in Scala 3
- Summary
- Functions
- Anonymous Functions
- Function Variables
- Partial Functions
- Eta-Expansion
- Higher-Order Functions
- Write Your Own map Method
- Creating a Method That Returns a Function
- Summary
- Packaging and Imports
- Scala Collections
- Collections Types
- Collections Methods
- Summary
- Functional Programming
- What is Functional Programming?
- Immutable Values
- Pure Functions
- Functions Are Values
- Functional Error Handling
- Summary
- Types and the Type System
- Inferred Types
- Generics
- Intersection Types
- Union Types
- Algebraic Data Types
- Variance
- Opaque Types
- Structural Types
- Dependent Function Types
- Other Types
- Contextual Abstractions
- Extension Methods
- Context Parameters
- Context Bounds
- Given Imports
- Type Classes
- Multiversal Equality
- Implicit Conversions
- Summary
- Concurrency
- Scala Tools
- Building and Testing Scala Projects with sbt
- Worksheets
- Interacting with Java
- Scala for Java Developers
- Scala for JavaScript Developers
- Scala for Python Developers
- Where To Go Next