iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 4
0

如何讓你的程式不失控呢?當然就是要學好控制流程啦!今天我們來談談 Conditional statements,也就是如何改變程式執行的流程。其實就是像 if , switch , while 等等之類的唷!


今日挑戰內容

給一個整數 n, 如果是奇數或者是 6~20 之間的偶數就說他是 Weird,反之就是 Not Weird。
那就讓我們看看各語言有什麼名堂吧!

Scala

import scala.io.StdIn._

object Solution {
    def main(args: Array[String]) {
        val n = readInt
        n % 2 match {
            case 0 => n match {
                case x if (1 < x && x < 6) || x > 20 => println("Not Weird")
                case _ => println ("Weird")
            }
            case _ => println("Weird")
        }
    }
}
  • 我們可以發現我們的題目是需要做很多的邏輯判斷,一般來說,我們直覺會想到去使用很多的 if-else 來去做判斷。但是在 Scala 裡面,有個更厲害的東西叫做 Pattern matching,我們先前在 Rust 也有稍微提過。Pattern matching 除了達到像 Switch 的效果,還能幫助我們去解析出被 Match 的 Object 的一些屬性 (之後會再提到),甚至是可以幫助我們判斷型別等等。在這裡我們透過 match 來做到像是 Switch 的功能,判斷 n % 2 會是什麼樣的 "Pattern" 並且做後續邏輯處理。而 n % 2 我們知道不是 0 就是 1,而這裡主要需要處理的是等於 0 的情況,也就是 n 是偶數。
  • match 一定會跟著很多的 case ,也就是 Patterns。這裡我們有個巢狀的 match 。先來看最外層的 match 有兩個 case: case 0 , case _case 0 表示當 n % 2 等於 0 時,就做後面的事 ( =>後面的邏輯),而 case _ 是處理 Default 的行為,也就是當上面的 Case 都不成立時所使用。
  • 接著我們看內層的 match ,這裡是要判斷 n 是否介於 1~6 以及大於 12,第一個 case 表示假設 xn,且 xif 後面的判斷成立,就做 => 後面的事情。這時候的 if 又叫做 Pattern guard,也就是讓我們再加上對於是否吻合 Pattern 的判斷。
  • 舉個有趣的例子,如果我們要宣告 x 在某個條件下是 1,其他則是 2 時,我們可以這樣寫 val x = if (...) 1 else 2 ,為什麼?因為我們說過 Scala 本身也是個 expression based 的語言,if (...) 1 else 2 這個表達式最後會被計算而產生一個值,所以當然就可以拿來賦予給 x 囉!更深入的 Pattern matching 可參考這裡
  • Scala 是 Short circuit,例如 A && BA || B 如果已經可以從 A知道整個結果是 false/true,那後者( B)就不會再被執行了。

Python 3

n = int(input())

result = 'Weird'

if n % 2 == 0 and not n in range(6, 21):
    result = 'Not ' + result
    
print(result)
  • 這裡的概念是,如果 n 是偶數 (n % 2 等於 0) 且 n 不在 6~20 話就印出 Not Weird,反之則是 Weird。因為 Python 的部分滿簡單的,我們就來看看幾個比較特別的地方。
  • 在 Python 的 if 是沒有括號的,而且 Code block 一樣是靠縮排。其他的語言在做 And/Or 的判斷時,通常會寫成像是 &&|| ,但在 Python 的世界,用比較口語的方式,像是這裡的 and, not 或是 or ,其中 not 就是反向的意思。 not n in range(6, 21) ,就是說 n 不在 range(6, 21) ,而 range(6, 21) 代表的是 6~20 唷 (不是 21), range(start, stop, step) 是 Python 內建的函數,可以產生數字序列, start 是起始點, stop 是終點,而 step 表示一次跳多少個數字。range 常被用在 loop 結構中,當我們需要去執行多次動作的時候,可以利用 range 產生的數字序列來代表執行的次數。我相信之後我們就會再跟他見面了。
  • 最後我們來看看 short-circuit 。Python 是 short-circuit,舉個例子 A and B 如果 Afalse,那麼 B 就不會被執行了,因為已經可以確定整個結果一定是 false;反之, A or B ,如果 Atrue,那麼 B 也不會被執行了。

Golang

package main

import (
	"fmt"
	"os"
	"bufio"
	"strconv"
)

func main() {
	
  	scanner := bufio.NewScanner(os.Stdin)
  	scanner.Scan()
  	n, _ := strconv.ParseInt(scanner.Text(), 10, 64)

	if n % 2 != 0 {
    		fmt.Println("Weird")
  	} else {
    		switch {
      			case (6 <= n) && (n <= 20): fmt.Println("Weird")
      			default: fmt.Println("Not Weird")
    		}
 	}

} 
  • Golang 的部份我們也是用 if 搭配 switch 。Golang 的 if 一樣不用括號。而 Golang 的 switch 就不是 Pattern matching 了,而是一般的 switch ,也是就看值是多少,找到對應的 case 然後執行程式 (可參考這裡)。如果都沒有對應的 case 就執行 default 的內容。而這裡比較特別的是,我們不是 switch xxx {} ,而是把判斷邏輯也寫在 case 裡頭: case (6 <= n) && (n <= 20)
  • 如果你要透過 switch 來判斷型別也可以,但是因為 Golang 不是 Pattern matching 的概念,所以你必須先把欲判斷值的型別取出來再用各個 case 進行比較判斷,也就是當作值來判斷,如下:
switch t := x.(type) {
        case bool:
            fmt.Println("I'm a bool")
        case int:
            fmt.Println("I'm an int")
        default:
            fmt.Printf("Don't know type %T\n", t)
}
  • Golang 一樣也是 short-circuit 唷!

Rust

use std::io;

fn main () {
    let mut input = String::new();

    io::stdin().read_line(&mut input)
        .expect("Error reading input");

    let n :i32 = match input.trim().parse() {
        Ok(num) => num,
        Err(_) => 0,
    };

    match n {
      x if x % 2 != 0 => println!("Weird"),
      6 ... 20 => println!("Weird"),
      _ => println!("Not Weird")
    }
}
  • 既然 Rust 有 Pattern matching,那麼我們就也用 Pattern matching 的方式來解決這個問題吧!基本上跟 Scala 的部分相當類似,我們也是把我們想要 match 的對象放在 match 之後,也就是 n ,再來下一行是說,假設 xn ,如果 x % 2 != 0 表示這個 Pattern 有 Match 到,所以就執行 => 後面的內容。這裡的 if 在 Rust 也是稱作 Guard。比較酷的是下一行,Rust 可以讓我們 Match 一個 Range,在這裡 6 ... 20 表示 6 到 20 (有包含 20 唷!)。除此之外還有像是可以 Match 像是'a' ... 'j' 表示 a~j 的字母。而最後的 是 Default Pattern。
  • Rust 的 Pattern matching 還有很多有趣的可以參考這裡
  • Rust 一樣也是 short-circuit 唷!

結語

今天的內容似乎比較簡單,不過下一章應該就精彩了!我們要來談談 Class 和 Struct 囉!明天見!


上一篇
[Day 2] 你不知道的 Operator!
下一篇
[Day 4] 類別與結構你選誰?
系列文
30 天把自己榨好榨滿的四週四語言大挑戰!30

尚未有邦友留言

立即登入留言