Files
kotlin-fork/docs/confluence.jetbrains.com/Kotlin/40700138_Control+structures.confluence
T
2012-05-30 14:41:40 +04:00

207 lines
5.5 KiB
Plaintext

{anchor:If}
h3. If expression
In [Kotlin], *if* is an _expression_, i.e. it returns a value. Therefore there is not _ternary operator_ ({{condition ? then : else}}), because ordinary *if* works fine in this role. Consider the following examples:
{jet}
// Traditional usage
var max = a
if (a < b)
max = b
// With else
var max : Int
if (a > b)
max = a
else
max = b
// As expression
val max = if (a > b) a else b
{jet}
*If* branches can be blocks, and the last expression is the value of a block:
{jet}
val max = if (a > b) {
print("Choose a")
a
}
else {
print("Choose b")
b
}
{jet}
When *if* has only one branch, or one of its branches results in [{{Unit}}|Functions#Unit], it's type is [{{Unit}}|Functions#Unit].
See the grammar for *if* [here|Grammar#if].
{anchor:When}
h3. When expression
*When* replaces the *switch* operator of *C*\-like languages. In the simplest form it looks like this:
{jet}
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // Note the block
print("x is neither 1 nor 2")
}
}
{jet}
*When* matches its argument against all branches consequently until some branch condition is satisfied. *When* is an _expression_ and results in satisfied branch's right hand side. If some of its branches return result in a value of type [{{Unit}}|Functions#Unit], the whole expression has type [{{Unit}}|Functions#Unit].
Note that the *else* branch is mandatory, unless the compiler can prove that all possible cases are covered with branch conditions.
If many cases should be handled in the same way, the branch conditions may be combined with a comma:
{jet}
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
{jet}
We can use arbitrary expressions (not only constants) as branch conditions:
{jet}
when (x) {
parseInt(s) -> print("s encodes x")
else -> print("s does not encode x")
}
{jet}
One can also check a value for being *in* or *\!in* a [range|Ranges]:
{jet}
when (x) {
in 1..10 -> print("x is in the range")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
{jet}
*When*\-expressions support [pattern matching|Pattern matching] through {{is}} and {{\!is}}:
{jet}
when (tuple) {
is #(1, 2) -> ...
is #(val a, 3) -> print(a) // binding a to the first element of the tuple
!is #(*, 1100) -> ...
else -> ...
}
{jet}
We do not expand on the pattern matching here. For details, look at [this page|Pattern matching].
{anchor:bare-when}
*When* can also be used as a replacement for an *if*\-*else*\-*if* chain. If no argument is supplied, the branch conditions are simply boolean expressions, and a branch is executed when its condition is true:
{jet}
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
{jet}
{anchor:continue-when}
h4. Continue inside {{when}}
Inside *when* expressions, *continue* jumps to the next branch condition, if any:
{jet}
when (x) {
in 1..100 ->
if (x.isOdd())
continue // Jump to the next branch, i.e. '3, 101 -> ...'
else
print("Even between 1 and 100")
3, 101 -> print("3 or 101")
1000 -> <error desc="'continue' is not allowed in the last branch">continue</error> // Error: continue is not allowed in the last branch
}
{jet}
This mechanism replaces the concept of _guards_ available in other languages. I.e. in *Scala* one has _guard_ *{_}if{_}* _expressions_ in *match* (that corresponds to *when*):
{code:Scala}
// Scala
term match {
case Fun(x, Var(y)) if x == y -> print(x)
case _ -> print("Nope!")
}
{code}
This can be rewritten in [Kotlin] with as follows:
{jet}
when(term) {
is Fun#(val x, Var#(val y)) -> { if (x != y) continue; print(x) }
else -> print("Nope!")
}
{jet}
See [Returns and jumps] for more information about *continue*.
See the grammar for *when* [here|Grammar#when].
See also [Pattern matching].
{note:title=Continue in when is not implemented yet}See the corresponding [issue|http://youtrack.jetbrains.com/issue/KT-771]{note}
{anchor:Loops}
{anchor:For}
h3. For loop
*For* loop iterates through anything that provides an _iterator_. The syntax is as follows:
{jet}
for (item in collection)
print(item)
{jet}
One can specify a type and *val* or *var* for the loop variable. The body can be a block.
{jet}
for (val item : Int in ints) {
// ...
}
{jet}
As mentioned before, *for* iterates through anything that provides and *iterator*, i.e.
# has an instance\- or extension-function {{iterator()}}, whose return type
# has an instance\- or extension-function {{next()}}, and
# either
## a property {{hasNext}} of type {{Boolean}}, or
## a function {{hasNext()}} that returns {{Boolean}}.
If you want to iterate through an [array|Basic types#Arrays] or list with an index, you can do it this way:
{jet}
for (i in array.indices)
print(array[i])
{jet}
Note that this "iteration through a range" is compiled down to optimal implementation with no extra objects created.
See the grammar for *for* [here|Grammar#for].
{anchor:while}
h3. While and do..while loops
*While* and *do*..*while* work as usual:
{jet}
while(x > 0) {
x--
}
do {
val y = retrieveData()
} while(y != null) // y is visible here!
{jet}
See the grammar for *while* [here|Grammar#while].
h3. Break and continue in loops
[Kotlin] supports traditional *break* and *continue* operators in loops. See more here [Returns and jumps].
h3. Try expression
See [Exceptions] for the details.
h3. What's next
* [Function literals]
* [Returns and jumps]
* [Ranges]
* [This expressions]
* [Tuples]
* [Type casts]