Làm cách nào để thực hiện câu lệnh one-liner if else?


104

Tôi có thể viết một câu lệnh if-else đơn giản với phép gán biến trong go (golang) như tôi làm trong php không? Ví dụ:

$var = ( $a > $b )? $a: $b;

Hiện tại tôi phải sử dụng những thứ sau:

var c int
if a > b {
    c = a
} else {
    c = b
}

Xin lỗi, tôi không thể nhớ tên nếu câu lệnh kiểm soát này và tôi không thể tìm thấy thông tin trong trang web hoặc thông qua tìm kiếm của google. : /


4
Nó được gọi là toán tử bậc ba ... và không, Go không có.
Simon Whitehead

6
Tôi tin rằng từ mà bạn đang tìm kiếm là "ternary"
BenjaminRH


10
Chỉ cần làm rõ, một toán tử bậc ba là bất kỳ toán tử nào của bậc 3, đó là bất kỳ toán tử nào liên kết 3 biểu thức con. C xảy ra chỉ có một toán tử như vậy. Đó là lý do tại sao nó thường được gọi là toán tử bậc ba. Tuy nhiên, tên thật của nó là "toán tử điều kiện".
thwd

Câu trả lời:


131

Như các nhận xét đã đề cập, Go không hỗ trợ lót một bậc ba. Hình thức ngắn nhất mà tôi có thể nghĩ ra là:

var c int
if c = b; a > b {
    c = a
}

Nhưng xin đừng làm vậy, nó không đáng và sẽ chỉ gây nhầm lẫn cho những người đọc mã của bạn.


83
@thoroc Tôi thực sự có thể sẽ tránh điều đó trong cuộc sống thực, vì nó không phải là IMHO trực quan, không đáng để lưu 2 dòng để dễ đọc hơn.
Not_a_Golfer

14
@thoroc, hãy lắng nghe những gì Not_a_Golfer nói. Bạn nên cố gắng viết phần mềm có thể bảo trì được chứ không phải khoe khoang. Thủ thuật gọn gàng là gọn gàng nhưng anh chàng tiếp theo đọc mã của bạn (bao gồm cả bạn trong vài tháng / năm) sẽ không đánh giá cao chúng.
kostix

3
Nó phụ thuộc vào khả năng đọc. Tôi nghĩ điều này dễ đọc hơn, nhưng giống như bất cứ điều gì khác, nó có thể bị lạm dụng. Nếu bạn cần khai báo một biến không cần thiết bên ngoài khối if, thì tôi nghĩ đây là một biến chiến thắng.
arjabbar

@Not_a_Golfer nó không chỉ dễ đọc bởi tính đối xứng, sự tương phản về cấu trúc với ý định còn nằm trong mã đã biên dịch, đôi khi thậm chí có thêm chi phí cho một lần khởi tạo dư thừa.
Wolf,

5
Ôi, vui quá, hãy nhìn xem cờ vây đã kiếm được bao nhiêu khi không có toán tử bậc ba. Ngoài các nhận xét về khả năng đọc được thực hiện, bạn đã thay đổi cấu trúc được đánh giá một cách lười biếng trong đó chỉ một nhánh được chạy đến một nhánh mà nhánh đầu tiên luôn chạy và nhánh thứ hai có thể được chạy thêm vào.
itbruce

29

Tôi thường sử dụng như sau:

c := b
if a > b {
    c = a
}

về cơ bản giống với @ Not_a_Golfer's nhưng sử dụng kiểu suy luận .


4
Với cùng một khuyết điểm: bạn phức tạp hóa sự hiểu biết khi sử dụng một giải pháp không đối xứng cho một yêu cầu rõ ràng là đối xứng.
Wolf,

2
Và khuyết điểm tương tự của việc biến những gì nên là một cấu trúc được đánh giá một cách lười biếng, nơi chỉ một trong hai nhánh sẽ được sử dụng thành một trong đó một nhánh sẽ luôn được đánh giá, đôi khi là cả hai (trong trường hợp đó, đánh giá đầu tiên là thừa)
itsbruce

1
Tùy thuộc vào trường hợp sử dụng, điều này vẫn có thể rất hữu ích. Ví dụ: listeningPath := "production.some.com"; if DEBUG { listeningPath := "development.some.com" }Tốc độ tương tự như bậc ba dành cho sản xuất, và khả năng đọc khá tốt.
Levite

Tôi thường khóc khi cố ý lãng phí chu kỳ CPU.
alessiosavi ngày

28

Như những người khác đã đề cập, Gokhông hỗ trợ các lớp lót một bậc ba. Tuy nhiên, tôi đã viết một hàm tiện ích có thể giúp bạn đạt được những gì bạn muốn.

// IfThenElse evaluates a condition, if true returns the first parameter otherwise the second
func IfThenElse(condition bool, a interface{}, b interface{}) interface{} {
    if condition {
        return a
    }
    return b
}

Dưới đây là một số trường hợp thử nghiệm để chỉ ra cách bạn có thể sử dụng nó

func TestIfThenElse(t *testing.T) {
    assert.Equal(t, IfThenElse(1 == 1, "Yes", false), "Yes")
    assert.Equal(t, IfThenElse(1 != 1, nil, 1), 1)
    assert.Equal(t, IfThenElse(1 < 2, nil, "No"), nil)
}

Để cho vui, mình viết thêm các hàm tiện ích hữu ích như:

IfThen(1 == 1, "Yes") // "Yes"
IfThen(1 != 1, "Woo") // nil
IfThen(1 < 2, "Less") // "Less"

IfThenElse(1 == 1, "Yes", false) // "Yes"
IfThenElse(1 != 1, nil, 1)       // 1
IfThenElse(1 < 2, nil, "No")     // nil

DefaultIfNil(nil, nil)  // nil
DefaultIfNil(nil, "")   // ""
DefaultIfNil("A", "B")  // "A"
DefaultIfNil(true, "B") // true
DefaultIfNil(1, false)  // 1

FirstNonNil(nil, nil)                // nil
FirstNonNil(nil, "")                 // ""
FirstNonNil("A", "B")                // "A"
FirstNonNil(true, "B")               // true
FirstNonNil(1, false)                // 1
FirstNonNil(nil, nil, nil, 10)       // 10
FirstNonNil(nil, nil, nil, nil, nil) // nil
FirstNonNil()                        // nil

Nếu bạn muốn sử dụng bất kỳ cái nào trong số này, bạn có thể tìm thấy chúng ở đây https://github.com/shomali11/util


12

Cảm ơn vì đã chỉ ra câu trả lời chính xác.

Tôi vừa kiểm tra Câu hỏi thường gặp về Golang (duh) và nó nói rõ, điều này không khả dụng bằng ngôn ngữ:

Go có toán tử ?: không?

Không có hình thức bậc ba trong cờ vây. Bạn có thể sử dụng những cách sau để đạt được kết quả tương tự:

if expr {
    n = trueVal
} else {
    n = falseVal
}

thông tin bổ sung được tìm thấy có thể được quan tâm về chủ đề:


nó cũng có thể trong một dòng var c int; if a > b { c = a } else { c = b }:? Nhưng tôi khuyên bạn nên giữ nó trong 5 dòng để tạo thành một khối sáng cho người đọc giải trí;)
Wolf

7

Một cách khả thi để thực hiện việc này chỉ trong một dòng bằng cách sử dụng bản đồ, đơn giản là tôi đang kiểm tra xem liệu a > bđó có phải là truetôi đang gán ccho người akhác khôngb

c := map[bool]int{true: a, false: b}[a > b]

Tuy nhiên, điều này có vẻ tuyệt vời nhưng trong một số trường hợp, nó có thể KHÔNG phải là giải pháp hoàn hảo vì thứ tự đánh giá. Ví dụ: nếu tôi đang kiểm tra xem một đối tượng nilcó lấy một số thuộc tính ra khỏi nó hay không, hãy xem đoạn mã sau, đoạn mã này sẽ panicđề phòngmyObj equals nil

type MyStruct struct {
   field1 string
   field2 string 
}

var myObj *MyStruct
myObj = nil 

myField := map[bool]string{true: myObj.field1, false: "empty!"}[myObj != nil}

Bởi vì bản đồ sẽ được tạo và xây dựng đầu tiên trước khi đánh giá điều kiện nên trong trường hợp myObj = nilnày sẽ chỉ đơn giản là hoảng sợ.

Không quên đề cập rằng bạn vẫn có thể thực hiện các điều kiện chỉ trong một dòng đơn giản, hãy kiểm tra như sau:

var c int
...
if a > b { c = a } else { c = b}

4

Sử dụng hàm lambda thay vì toán tử bậc ba

ví dụ 1

để cung cấp số nguyên tối đa

package main

func main() {

    println( func(a,b int) int {if a>b {return a} else {return b} }(1,2) )
}

Ví dụ 2

Giả sử bạn có must(err error)chức năng này để xử lý lỗi và bạn muốn sử dụng nó khi một điều kiện không được đáp ứng. (thưởng thức tại https://play.golang.com/p/COXyo0qIslP )

package main

import (
    "errors"
    "log"
    "os"
)

// must is a little helper to handle errors. If passed error != nil, it simply panics.
func must(err error) {
    if err != nil {
        log.Println(err)
        panic(err)
    }
}

func main() {

    tmpDir := os.TempDir()
    // Make sure os.TempDir didn't return empty string
    // reusing my favourite `must` helper
    // Isn't that kinda creepy now though?
    must(func() error {
        var err error
        if len(tmpDir) > 0 {
            err = nil
        } else {
            err = errors.New("os.TempDir is empty")
        }
        return err
    }()) // Don't forget that empty parentheses to invoke the lambda.
    println("We happy with", tmpDir)
}

2
cách tiếp cận thú vị, Nó có thể hữu ích trong các trường hợp phức tạp hơn. :)
thoroc

1

Đôi khi, tôi cố gắng sử dụng chức năng ẩn danh để xác định và gán diễn ra ở cùng một dòng. như dưới đây:

a, b = 4, 8

c := func() int {
    if a >b {
      return a
    } 
    return b
  } ()

https://play.golang.org/p/rMjqytMYeQ0


0

Một cấu trúc rất giống nhau có sẵn trong ngôn ngữ

**if <statement>; <evaluation> {
   [statements ...]
} else {
   [statements ...]
}*

*

I E

if path,err := os.Executable(); err != nil {
   log.Println(err)
} else {
   log.Println(path)
}

0

Bạn có thể sử dụng một đóng cho điều này:

func doif(b bool, f1, f2 func()) {
    switch{
    case b:
        f1()
    case !b:   
        f2()
    }
}

func dothis() { fmt.Println("Condition is true") }

func dothat() { fmt.Println("Condition is false") }

func main () {
    condition := true
    doif(condition, func() { dothis() }, func() { dothat() })
}

Điều duy nhất tôi có với cú pháp đóng trong Go là không có bí danh nào cho hàm trả về tham số 0 mặc định, sau đó nó sẽ đẹp hơn nhiều (hãy nghĩ như cách bạn khai báo các ký tự bản đồ, mảng và lát cắt chỉ với một tên kiểu).

Hoặc thậm chí là phiên bản ngắn hơn, như một người bình luận vừa đề xuất:

func doif(b bool, f1, f2 func()) {
    switch{
    case b:
        f1()
    case !b:   
        f2()
    }
}

func dothis() { fmt.Println("Condition is true") }

func dothat() { fmt.Println("Condition is false") }

func main () {
    condition := true
    doif(condition, dothis, dothat)
}

Bạn vẫn cần sử dụng một bao đóng nếu bạn cần cung cấp các tham số cho các hàm. Điều này có thể bị loại bỏ trong trường hợp truyền các phương thức chứ không chỉ là các hàm mà tôi nghĩ, trong đó các tham số là cấu trúc được liên kết với các phương thức.


Phiên bản ngắn hơndoif(condition, dothis, dothat)
vellotis

1
Vâng, điều đó thậm chí sẽ ngắn hơn, chỉ chuyển các hàm. Người ta chỉ phải có chức năng này một lần trong một thư viện tiện ích và bạn có thể sử dụng tất cả thông qua mã của mình.
Louki Sumirniy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.