I notice there is one line *(*int)(nil) = 0 in function throw
//go:nosplit
func throw(s string) {
// Everything throw does should be recursively nosplit so it
// can be called even when it's unsafe to grow the stack.
systemstack(func() {
print("fatal error: ", s, "\n")
})
gp := getg()
if gp.m.throwing == 0 {
gp.m.throwing = 1
}
fatalthrow()
*(*int)(nil) = 0 // not reached
}
What does *(*int)(nil) = 0 means? and since this line *(*int)(nil) = 0 could NOT be reached, why it is here? any special usage?
The line:
*(*int)(nil) = 0
Tries to dereference a nil pointer and assign a value to it, which is always a runtime panic. The code should not reach this line, ever, but if it would anyhow (e.g. a faulty code change in the future), it would panic so the error could be detected and wouldn't go unnoticed.
It's common sense to do something similar in your code too, but with a more obvious "construct" such as panic("unreachable"). For example:
func sign(a int) string {
switch {
case a > 0:
return "Positive"
case a < 0:
return "Negative"
case a == 0:
return "Zero"
default:
panic("unreachable")
}
}
Note that in this example this is not just to detect errors early, it's also a requirement because to the compiler there would be no guarantee that a return statement would be reached. You could also move the panic("unreachable") statement after the switch (instead of the default branch), it's a matter of taste.
If you would change the above function to not return but print the sign, it would still be a good practice to leave the default branch to panic, although it's not a requirement in this variant:
func printSign(a int) {
switch {
case a > 0:
fmt.Println("Positive")
case a < 0:
fmt.Println("Negative")
case a == 0:
fmt.Println("Zero")
default:
panic("unreachable")
}
}
Related
In the slide #5 of the flow control Go Tour I don't understand how the return keyword is working inside the function sqrt().
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
I understand the code with a else clause like this
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}else{
return fmt.Sprint(math.Sqrt(x))
}
}
This code executes without problems, but the linter, golint, in VsCode complains about the else clause.
Does the statement return sqrt(-x) + "i" inside the first if block ends the execution of the function ?
how is it exactly working ?
As with most (if not all?) the first return statement the compiler hits will exit the function and not continue.
It's warning reported by go linter. Code underneath is valid.
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
This one below is also valid, but will generate some warning.
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
} else {
return fmt.Sprint(math.Sqrt(x))
}
}
Basically if there is if statement and the body contains return statement, better not to use else block.
The Go Programming Language Specification
Return statements
A "return" statement in a function F terminates the execution of F,
and optionally provides one or more result values. Any functions
deferred by F are executed before F returns to its caller.
The specification defines the language. return terminates the function.
Go Code Review Comments
Indent Error Flow
Try to keep the normal code path at a minimal indentation, and indent
the error handling, dealing with it first. This improves the
readability of the code by permitting visually scanning the normal
path quickly. For instance, don't write:
if err != nil {
// error handling
} else {
// normal code
}
Instead, write:
if err != nil {
// error handling
return // or continue, etc.
}
// normal code
While either will work, as a matter of style, remove the unnecessary else and indentation. It's a similar to error flow indentation.
I'm trying to implement a default value according to the option 1 of the post Golang and default values. But when I try to do go install the following error pops up in the terminal:
not enough arguments in call to test.Concat1
have ()
want (string)
Code:
package test
func Concat1(a string) string {
if a == "" {
a = "default-a"
}
return fmt.Sprintf("%s", a)
}
// other package
package main
func main() {
test.Concat1()
}
Thanks in advance.
I don't think what you are trying to do will work that way. You may want to opt for option #4 from the page you cited, which uses variadic variables. In your case looks to me like you want just a string, so it'd be something like this:
func Concat1(a ...string) string {
if len(a) == 0 {
return "a-default"
}
return a[0]
}
Go does not have optional defaults for function arguments.
You may emulate them to some extent by having a special type
to contain the set of parameters for a function.
In your toy example that would be something like
type Concat1Args struct {
a string
}
func Concat1(args Concat1Args) string {
if args.a == "" {
args.a = "default-a"
}
return fmt.Sprintf("%s", args.a)
}
The "trick" here is that in Go each type has its respective
"zero value", and when producing a value of a composite type
using the so-called literal, it's possible to initialize only some of the type's fields, so in our example that would be
s := Concat1(Concat1Args{})
vs
s := Concat1(Concat1Args{"whatever"})
I know that looks clumsy, and I have showed this mostly for
demonstration purpose. In real production code, where a function
might have a dozen of parameters or more, having them packed
in a dedicate composite type is usually the only sensible way
to go but for a case like yours it's better to just explicitly
pass "" to the function.
Golang does not support default parameters. Accordingly, variadic arguments by themselves are not analogous. However, variadic functions with the use of error handling can 'resemble' the pattern. Try the following as a simple example:
package main
import (
"errors"
"log"
)
func createSeries(p ...int) ([]int, error) {
usage := "Usage: createSeries(<length>, <optional starting value>), length should be > 0"
if len(p) == 0 {
return nil, errors.New(usage)
}
n := p[0]
if n <= 0 {
return nil, errors.New(usage)
}
var base int
if len(p) == 2 {
base = p[1]
} else if len(p) > 2 {
return nil, errors.New(usage)
}
vals := make([]int, n)
for i := 0; i < n; i++ {
vals[i] = base + i
}
return vals, nil
}
func main() {
answer, err := createSeries(4, -9)
if err != nil {
log.Fatal(err)
}
log.Println(answer)
}
Default parameters work differently in Go than they do in other languages. In a function there can be one ellipsis, always at the end, which will keep a slice of values of the same type so in your case this would be:
func Concat1(a ...string) string {
but that means that the caller may pass in any number of arguments >= 0. Also you need to check that the arguments in the slice are not empty and then assign them yourself. This means they do not get assigned a default value through any kind of special syntax in Go. This is not possible but you can do
if a[0] == "" {
a[0] = "default value"
}
If you want to make sure that the user passes either zero or one strings, just create two functions in your API, e.g.
func Concat(a string) string { // ...
func ConcatDefault() string {
Concat("default value")
}
In some languages it's necessary or cleaner to do iteration by providing a callback function that receives items and returns a boolean that indicates whether to continue or stop the iteration.
Which is the preferred value to indicate desire to stop/continue? Why? What precedents exist?
Example in Go:
func IntSliceEach(sl []int, cb func(i int) (more bool)) (all bool) {
for _, i := range sl {
if !cb(i) {
return false
}
}
return true
}
Which is the preferred value to indicate desire to stop/continue?
true for continue
Why?
Example 1:
func example(i interface{}) {
if w, ok := i.(io.Writer); ok {
// do something with your writer, ok indicates that you can continue
}
}
Example 2:
var sum int = 0
it := NewIntStatefulIterator(int_data)
for it.Next() {
sum += it.Value()
}
In both cases true (ok) indicates that you should continue. So I assume that it would be way to go in your example.
Foreword: The following answer applies to a callback function which decides based on the current item(s) whether the loop should terminate early - this is what you asked.
This is not to be confused with a function that progresses and reports if there are more elements to process, where a true return value is generally accepted to signal that there are more elements (for which a good example is Scanner.Scan()), and whose typical use is:
scanner := bufio.NewScanner(input)
for scanner.Scan() {
// Process current item (line):
line := scanner.Text()
fmt.Println(line) // Do something with line
}
Sticking to bool return type
Usually returning true to indicate termination results in code that is easier to read. This is due to the nature of for: if you do nothing, for continues, so you have to explicitly break if you want to terminate early, so having a clean termination condition is more common.
But it's a matter of taste. You may go whichever you like, but what's important is to name your callback function in a meaningful way that will clearly state what its return value means, and thus looking at the code (the condition in which it is used) will be easily understandable.
For example the following names are good and the return value is unambiguous:
// A return value of true means to terminate
func isLast(item Type) bool
func terminateAfter(item Type) bool
func abort(item Type) bool
// A return value of true means to continue (not to terminate)
func keepGoing(item Type) bool
func carryOn(item Type) bool
func processMore(item Type) bool
Using these results in easily understandable code:
for i, v := range vals {
doSomeWork()
if terminateAfter(v) {
break // or return
}
}
for i, v := range vals {
doSomeWork()
if !keepGoing(v) {
break // or return
}
}
// Or an alternative to the last one (subjective which is easier to read):
for i, v := range vals {
doSomeWork()
if keepGoing(v) {
continue
}
break
}
As negative examples, the following callback function names are bad as you can't guess what their return value mean:
// Bad: you can't tell what return value of true means just by its name:
func test(item Type) bool
func check(item Type) bool
Having error return type
It's also common for the callback to not just test but also do some work with the passed item. In these cases it is meaningful to return an error instead of a bool. Doing so, obviously the nil return value indicates success (and to continue), and a non-nil value indicates error and that processing should stop.
func process(item Type) error
for i, v := range vals {
if err := process(v); err != nil {
// Handle error and terminate
break
}
}
Having enum-like return value
Also if multiple return values have meaning, you may choose to define constants for return values, which you can name meaningfully.
type Action int
const (
ActionContinue Action = iota
ActionTerminate
ActionSkip
)
func actionToTake(item Type) Action
for i, v := range vals {
switch actionToTake(v) {
case ActionSkip:
continue
case ActionTerminate:
return
}
doSomeWork()
}
Getting the above error with the following code in Playground Xcode 7.1.1:
import Cocoa
func countDivisors(number:Int) -> Int
{
var c = 0
for i in 1 ... number
{
if number % i == 0 { ++c }
}
return c
}
func isPrime(number:Int) -> Bool
{
return countDivisors(number) == 2
}
isPrime(2);
for i in 0 ..< 100
{
var f:Bool = isPrime(i)
print("\(i): \(f)")
}
The error occurs on the line
var f:Bool = isPrime(i)
I already re-installed Xcode but error still appears. Does anyone know the reason behind this?
The reason you get "EXC_BAD_INSTRUCTION" is because the for loop's range operator cannot form a range with end value as 0. Your range operator's end value should be greater or equal to the start value.
From apple docs,
The closed range operator (a...b) defines a range that runs from a to b, and includes the values a and b. The value of a must not be greater than b.
This will work
for i in 1...1 {
//--
}
but not this
for i in 1...0 {
//--
}
When the line var f:Bool = isPrime(i) is called, initial value of i is 0, division by zero gives an unknown value. Better change your loop to for i in 1 ..< 100
I have a type method that mutates the type's fields. It takes no arguments and returns nothing. The bulk of the method is a switch block. I want to be able to "short-circuit" out of the switch block with a no-op. Before I refactored it into a type method, I would've just returned out of the function, but that's out. Removing the case would break the logic of the method--the default case mutates state, which I don't want to do if this case is matched. I need the equivalent of Python's pass, basically.
Code:
func (parser *Parser) endSectionName () {
state = parser.State
buffer = parser.buffer
results = parser.results
switch {
case state.HasFlag(IN_ESCAPED) {
// ???
}
case !inSection(state) {
return state, NotInSectionError
}
case !state.HasFlag(IN_SECTION_NAME) {
state.Reset()
return state, errors.New("Parsing error: Not in section name")
}
default {
state.RemoveFlag(IN_SECTION_NAME)
s := buffer.String()
results[s] = new(Section)
buffer.Reset()
return state, nil
}
}
}
Unlike in other languages, in Go the control flow breaks at each case of a switch statement, control doesn't flow into the next case unless it is explicitly "asked" for with the fallthrough statement.
And also a statement is not required after the case (it can be empty). See this example:
i := 3
switch i {
case 3:
case 0:
fmt.Println("Hello, playground")
}
It will print nothing even though i==3 and there is no statement after case 3.
Same as this:
i := 3
switch {
case i == 3:
case i == 0:
fmt.Println("Hello, playground")
}
Try it on the Go Playground.