操作符及流程控制

操作符

算术操作符

dart

// +, -, /, *
// 位移操作符,<<,>>,&,|
// ~/ 除号,但是返回值为整数
// % 取模

go

js

// +, -, /, *
// 位移操作符,<<,>>,&,|,~,^

// 指数运算符:x ** y
// 余数运算符:x % y
// 自增运算符:++x 或者 x++
// 自减运算符:--x 或者 x--

python

# +, -, /, *
# 位移操作符,<<,>>,&,|,~,^

# 除法运算 (/) 永远返回浮点数类型
# 使用 // 运算符得到一个整数结果(忽略小数部分)
# 如果要计算余数,可以使用 %
# 使用 ** 运算符来计算乘方

相等大小操作符

dart

go

比较运算符==<也可以用来比较一个命名类型的变量和另一个有相同类型的变量, 或有着相同底层类型的未命名类型的值之间做比较。 但是如果两个值有着不同的类型,则不能直接进行比较:

var c Celsius
var f Fahrenheit
fmt.Println(c == 0)          // "true"
fmt.Println(f >= 0)          // "true"
fmt.Println(c == f)          // compile error: type mismatch
fmt.Println(c == Celsius(f)) // "true"!

js

python

类型判断操作符

dart

if (emp is Person) { // Type check
  emp.firstName = 'Bob';
}
// 使用 as 操作符可以简化上面的代码:
(emp as Person).firstName = 'Bob';
// 上面这两个代码效果是有区别的。
// 如果 emp 是 null 或者不是 Person 类型, 
// 则第一个示例使用 is 则不会执行条件里面的代码,
// 而第二个情况使用 as 则会抛出一个异常。

go

js

python

赋值操作符

dart

a = value;   // 给 a 变量赋值
b ??= value; // 如果 b 是 null,则赋值给 b;
             // 如果不是 null,则 b 的值保持不变

go

js

python

逻辑操作符

dart

go

js

// yes
if ('abc' === 'abc') {
  console.log('yes')
} else {
  console.log('no')
}

// yes
if ('abc' !== 'def') {
  console.log('yes')
} else {
  console.log('no')
}

// no
if (true && false) {
  console.log('yes')
} else {
  console.log('no')
}

// yes
if (true || false) {
  console.log('yes')
} else {
  console.log('no')
}

// yes
if (!false) {
  console.log('yes')
} else {
  console.log('no')
}

// no
if (0) {
  console.log('yes')
} else {
  console.log('no')
}

// no
if ('') {
  console.log('yes')
} else {
  console.log('no')
}

// no
if (undefined) {
  console.log('yes')
} else {
  console.log('no')
}

// no
if (null) {
  console.log('yes')
} else {
  console.log('no')
}

// yes
if (!!!null) {
  console.log('yes')
} else {
  console.log('no')
}

python

# yes
if "abc" == "abc":
    print("yes")
else:
    print("no")

# yes
if "abc" != "def":
    print("yes")
else:
    print("no")

# no
if True and False:
    print("yes")
else:
    print("no")

# yes
if True or False:
    print("yes")
else:
    print("no")

# yes
if not False:
    print("yes")
else:
    print("no")

# no
if 0:
    print("yes")
else:
    print("no")

# no
if "":
    print("yes")
else:
    print("no")

# no
if []:
    print("yes")
else:
    print("no")

# no
if None:
    print("yes")
else:
    print("no")

# yes
if not not not None:
    print("yes")
else:
    print("no")

位和移位操作符

dart

final value = 0x22;
final bitmask = 0x0f;

assert((value & bitmask)  == 0x02);  // AND
assert((value & ~bitmask) == 0x20);  // AND NOT
assert((value | bitmask)  == 0x2f);  // OR
assert((value ^ bitmask)  == 0x2d);  // XOR
assert((value << 4)       == 0x220); // Shift left
assert((value >> 4)       == 0x02);  // Shift right

go

js

python

条件表达式

Conditional expressions(条件表达式)/三元操作符

dart

go

js

const x = 2
const y = 3

// even
console.log(x % 2 === 0 ? 'even' : 'odd')
// odd
console.log(y % 2 === 0 ? 'even' : 'odd')

python

x = 2
y = 3

# even
print("even" if x % 2 == 0 else "odd")
# odd
print("even" if y % 2 == 0 else "odd")

级联操作符

dart

级联操作符 (..) 可以在同一个对象上 连续调用多个函数以及访问成员变量。

querySelector('#button') // Get an object.
  ..text = 'Confirm'   // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
// 上面的代码和下面的代码功能一样:
var button = querySelector('#button');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

go

js

python

条件成员访问

dart

?. 和 . 类似,但是左边的操作对象不能为 null, 例如 foo?.bar 如果 foo 为 null 则返回 null,否则返回 bar 成员

go

js

python

流程控制

if

dart

if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}

go

Go 的 if 语句与 for 循环类似,表达式外无需小括号 ( ) ,而大括号 { } 则是必须的。

package main
import (
  "fmt"
  "math"
)
func sqrt(x float64) string {
  if x < 0 {
    return sqrt(-x) + "i"
  }
  return fmt.Sprint(math.Sqrt(x))
}
func main() {
  fmt.Println(sqrt(2), sqrt(-4)) // 1.4142135623730951 2i
}


// 同 for 一样, if 语句可以在条件表达式前执行一个简单的语句。
// 该语句声明的变量作用域仅在 if 之内。
package main
import (
  "fmt"
  "math"
)
func pow(x, n, lim float64) float64 {
  if v := math.Pow(x, n); v < lim {
    return v
  }
  return lim
}
func main() {
  fmt.Println(
    pow(3, 2, 10),
    pow(3, 3, 20),
  )
}


// 在 if 的简短语句中声明的变量同样可以在任何对应的 else 块中使用。
package main
import (
  "fmt"
  "math"
)
func pow(x, n, lim float64) float64 {
  if v := math.Pow(x, n); v < lim {
    return v
  } else {
    fmt.Printf("%g >= %g\n", v, lim)
  }
  // 这里开始就不能使用 v 了
  return lim
}
func main() {
  fmt.Println(
    pow(3, 2, 10),
    pow(3, 3, 20),
  )
}

// 多个条件的时候
if integer == 3 {
  fmt.Println("The integer is equal to 3")
} else if integer < 3 {
  fmt.Println("The integer is less than 3")
} else {
  fmt.Println("The integer is greater than 3")
}

js

python

# 一个 if ... elif ... elif ... 序列
# 可以看作是其他语言中的 switch 或 case 语句的替代
x = int(input("Please enter an integer: "))

if x < 0:
    x = 0
    print('Negative changed to zero')
elif x == 0:
    print('Zero')
elif x == 1:
    print('Single')
else:
    print('More')

goto

dart

go

用goto跳转到必须在当前函数内定义的标签。

func myFunc() {
    i := 0
Here:   //这行的第一个词,以冒号结束作为标签
    println(i)
    i++
    goto Here   //跳转到Here去
}

js

python

For

dart

var message = new StringBuffer("Dart is fun");
for (var i = 0; i < 5; i++) {
  message.write('!');
}

// art for 循环中的闭包会捕获循环的 index 索引值
var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());

// 如果不需要当前遍历的索引
candidates.forEach((candidate) => candidate.interview());

// List 和 Set 等实现了 Iterable 接口的类还支持 for-in 形式的 遍历:
var collection = [0, 1, 2];
for (var x in collection) {
  print(x);
}

go

Go 只有一种循环结构:for 循环。 初始化语句通常为一句短变量声明,该变量声明仅在 for 语句的作用域中可见。

和 C、Java、JavaScript 之类的语言不同, Go 的 for 语句后面的三个构成部分外没有小括号, 大括号 { } 则是必须的。

// 如同C的for循环
for init; condition; post { }

// 如同C的while循环
for condition { }

// 如同C的for(;;)循环
for { }


package main
import "fmt"
func main() {
  sum := 1
  for i := 0; i < 10; i++ {
    sum *= 2
  }
  fmt.Println(sum) // 1024
}


// 初始化语句和后置语句是可选的。
// 相当于while循环
package main
import "fmt"
func main() {
  sum := 1
  for ; sum < 1000; {
    sum += sum
  }
  fmt.Println(sum) // 1024
}

// for 是 Go 中的 “while”
package main
import "fmt"
func main() {
  sum := 1
  for sum < 1000 {
    sum += sum
  }
  fmt.Println(sum)
}

// 无限循环
// 如果省略循环条件,该循环就不会结束
package main
func main() {
  for {
    // ...
  }
}


// 用牛顿法实现平方根函数
package main
import (
  "fmt"
)
func Sqrt(x float64) float64 {
  z := 1.8
  for n:=0; n<10; n++ {
    fmt.Println(z)
    z -= (z*z - x) / (2*z)
  }
  return z
}
func main() {
  fmt.Println(Sqrt(2))
}
// 1.8
// 1.4555555555555555
// 1.4148006785411367
// 1.4142136841942816
// 1.4142135623731005
// 1.414213562373095
// 1.4142135623730951
// 1.414213562373095
// 1.4142135623730951
// 1.414213562373095
// 1.4142135623730951


// range 子句能够帮你轻松实现循环
for key, value := range oldMap {
  newMap[key] = value
}

// 解析UTF-8, 将每个独立的Unicode码点分离出来
for pos, char := range "日本\x80語" { // \x80 是个非法的UTF-8编码
  fmt.Printf("字符 %#U 始于字节位置 %d\n", char, pos)
}

// 反转 a
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
  a[i], a[j] = a[j], a[i]
}

js

python

# Measure some strings:
words = ['cat', 'window', 'defenestrate']
for w in words:
    print(w, len(w))

# 如果在循环内需要修改序列中的值(比如重复某些选中的元素),推荐你先拷贝一份副本。
for w in words[:]:  # Loop over a slice copy of the entire list.
    if len(w) > 6:
        words.insert(0, w)
# ['defenestrate', 'cat', 'window', 'defenestrate']
# 如果写成 for w in words:,这个示例就会创建无限长的列表,
# 一次又一次重复地插入 defenestrate。

range

dart

go

for 循环的 range 形式可遍历切片或映射。 当使用 for 循环遍历切片时,每次迭代都会返回两个值。

package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
  for i, v := range pow {
    fmt.Printf("2**%d = %d\n", i, v)
  }
}
// 2**0 = 1
// 2**1 = 2
// 2**2 = 4
// 2**3 = 8
// 2**4 = 16
// 2**5 = 32
// 2**6 = 64
// 2**7 = 128


// 可以将下标或值赋予 _ 来忽略它。
package main
import "fmt"
func main() {
  pow := make([]int, 5)
  for i := range pow {
    pow[i] = 1 << uint(i) // == 2**i
  }
  for _, value := range pow {
    fmt.Printf("%d\n", value)
  }
}
// 1
// 2
// 4
// 8
// 16


// Go语言的range循环在处理字符串的时候,会自动隐式解码UTF8字符串。
for i, r := range "Hello, 世界" {
  fmt.Printf("%d\t%q\t%d\n", i, r, r)
}
// 0    'H'    72
// 1    'e'    101
// 2    'l'    108
// 3    'l'    108
// 4    'o'    111
// 5    ','    44
// 6    ' '    32
// 7    '世'    19990
// 10    '界'    30028

js

python

# 内置函数 range() 会派上用场。它生成算术级数:
>>> for i in range(5):
...     print(i)
...
0
1
2
3
4

# range也可以以另一个数字开头,或者以指定的幅度增加
range(5, 10)
   5, 6, 7, 8, 9

range(0, 10, 3)
   0, 3, 6, 9

range(-10, -100, -30)
  -10, -40, -70

# 要以序列的索引来迭代,您可以将 range() 和 len() 组合如下:
# 然而,在大多数这类情况下,使用 enumerate() 函数比较方便
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a)):
...     print(i, a[i])
...
0 Mary
1 had
2 a
3 little
4 lamb

# range 返回的是一个可迭代对象
>>> print(range(10))
range(0, 10)
>>> list(range(5))
[0, 1, 2, 3, 4]

While

dart

while (!isDone()) {
  doSomething();
}

do {
  printLine();
} while (!atEndOfPage());

go

js

python

BreakContinue

dart

// 使用 break 来终止循环:
while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}
// 使用 continue 来开始下一次循环:
for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}
// 上面的代码在实现 Iterable 接口对象上可以使用下面的写法:
candidates.where((c) => c.yearsExperience >= 5)
          .forEach((c) => c.interview());

go

js

// 1
// 2
// Fizz
// 4
// Buzz
for (let i = 1; i <= 100; i = i + 1) {
  if (i === 3) {
    console.log('Fizz')
    continue
  }

  if (i === 5) {
    console.log('Buzz')
    break
  }

  console.log(i)
}

python

# 1
# 2
# Fizz
# 4
# Buzz
for number in range(1, 101):
    if number == 3:
        print("Fizz")
        continue
    if number == 5:
        print("Buzz")
        break
    print(number)
# 循环语句可能带有一个 else 子句;
# 它会在循环遍历完列表 (使用 for) 或是在条件变为假 (使用 while) 的时候被执行,
# 但是不会在循环被 break 语句终止时被执行。

# 当和循环一起使用时,else 子句与 try 语句中的 else 子句的共同点多于 if 语句中的子句:
# try 语句中的 else 子句会在未发生异常时执行,
# 而循环中的 else 子句则会在未发生 break 时执行。

# 计算质数(素数)
>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, 'equals', x, '*', n//x)
...             break
...     else: # else 子句属于 for 循环, 不属于 if 语句。
...         # loop fell through without finding a factor
...         print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

# continue 语句也是借鉴自 C 语言,表示继续循环中的下一次迭代:
>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue
...     print("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9

pass

dart

go

js

python

while True:
    pass  # Busy-wait for keyboard interrupt (Ctrl+C)

class MyEmptyClass:
    pass

def initlog(*args):
    pass   # Remember to implement this!

Switch

dart

Dart 中的 Switch 语句使用 == 比较 integer、string、或者编译时常量。 比较的对象必须都是同一个类的实例(并且不是 其子类)

每个非空的 case 语句都必须有一个 break 语句。 另外还可以通过 continue、 throw 或 者 return 来结束非空 case 语句。 当没有 case 语句匹配的时候,可以使用 default 语句来匹配这种默认情况。

var command = 'OPEN';
switch (command) {
  case 'CLOSED':
    executeClosed();
    break;
  case 'PENDING':
    executePending();
    break;
  case 'APPROVED':
    executeApproved();
    break;
  case 'DENIED':
    executeDenied();
    break;
  case 'OPEN':
    executeOpen();
    break;
  default:
    executeUnknown();
}

// 在 Dart 中的空 case 语句中可以不要 break 语句:
var command = 'CLOSED';
switch (command) {
  case 'CLOSED': // Empty case falls through.
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

//  使用 continue 语句跳转到对应的标签(label)处继续执行
var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
    // Continues executing at the nowClosed label.
nowClosed:
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

go

switch 是编写一连串 if - else 语句的简便方法。 它运行第一个值等于条件表达式的 case 语句。

Go 只运行选定的 case,而非之后所有的 case。 Go 自动提供了在这些语言中每个 case 后面所需的 break 语句。 除非以 fallthrough 语句结束,否则分支会自动终止。 Go 的另一点重要的不同在于 switch 的 case 无需为常量,且取值不必为整数。

package main
import (
  "fmt"
  "runtime"
)
func main() {
  fmt.Print("Go runs on ")
  switch os := runtime.GOOS; os {
    case "darwin":
      fmt.Println("OS X.")
    case "linux":
      fmt.Println("Linux.")
    default:
      // freebsd, openbsd,
      // plan9, windows...
      fmt.Printf("%s.\n", os)
  }
}
// Go runs on Linux.


// switch 的 case 语句从上到下顺次执行,直到匹配成功时停止。
package main
import (
  "fmt"
  "time"
)
func main() {
  fmt.Println("When's Saturday?")
  fmt.Println(time.Now())
  fmt.Println(time.Saturday)
  today := time.Now().Weekday()
  switch time.Saturday {
    case today + 0:
      fmt.Println("Today.")
    case today + 1:
      fmt.Println("Tomorrow.")
    case today + 2:
      fmt.Println("In two days.")
    default:
      fmt.Println("Too far away.")
  }
}
// When's Saturday?
// 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
// Saturday
// Too far away.


// 没有条件的 switch 同 switch true 一样。
// 这种形式能将一长串 if-then-else 写得更加清晰。
package main
import (
  "fmt"
  "time"
)
func main() {
  t := time.Now()
  fmt.Println(t)
  switch {
    case t.Hour() < 12:
      fmt.Println("Good morning!")
    case t.Hour() < 17:
      fmt.Println("Good afternoon.")
    default:
      fmt.Println("Good evening.")
  }
}

func unhex(c byte) byte {
  switch {
  case '0' <= c && c <= '9':
    return c - '0'
  case 'a' <= c && c <= 'f':
    return c - 'a' + 10
  case 'A' <= c && c <= 'F':
    return c - 'A' + 10
  }
  return 0
}

// switch 并不会自动下溯,但 case 可通过逗号分隔来列举相同的处理条件。
func shouldEscape(c byte) bool {
  switch c {
  case ' ', '?', '&', '=', '#', '+', '%':
    return true
  }
  return false
}

js

python

defer

dart

go

defer 语句会将函数推迟到外层函数返回之后执行。 推迟调用的函数其参数会立即求值, 但直到外层函数返回前该函数都不会被调用。

推迟的函数调用会被压入一个栈中。 当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。

defer语句经常被用于处理成对的操作, 如打开、关闭、连接、断开连接、加锁、释放锁。通过defer机制

package main
import "fmt"
func main() {
  defer fmt.Println("world")
  fmt.Println("hello")
}
// hello
// world


// defer 栈
package main
import "fmt"
func main() {
  fmt.Println("counting")
  for i := 0; i < 10; i++ {
    defer fmt.Println(i)
  }
  fmt.Println("done")
}
// counting
// done
// 9
// 8
// 7
// 6
// 5
// 4
// 3
// 2
// 1
// 0


// Contents 将文件的内容作为字符串返回。
func Contents(filename string) (string, error) {
  f, err := os.Open(filename)
  if err != nil {
    return "", err
  }
  defer f.Close()  // f.Close 会在我们结束后运行。

  var result []byte
  buf := make([]byte, 100)
  for {
    n, err := f.Read(buf[0:])
    result = append(result, buf[0:n]...) // append 将在后面讨论。
    if err != nil {
      if err == io.EOF {
        break
      }
      return "", err  // 我们在这里返回后,f 就会被关闭。
    }
  }
  return string(result), nil // 我们在这里返回后,f 就会被关闭。
}


// 对匿名函数采用defer机制,可以使其观察函数的返回值。
func double(x int) (result int) {
  defer func() { fmt.Printf("double(%d) = %d\n", x,result) }()
  return x + x
}
_ = double(4)
// Output:
// "double(4) = 8"


// 被延迟执行的匿名函数甚至可以修改函数返回给调用者的返回值:
func triple(x int) (result int) {
  defer func() { result += x }()
  return double(x)
}
fmt.Println(triple(4)) // "12"

js

python