This commit is contained in:
wagslane
2023-05-01 15:25:27 -06:00
parent f8912668b8
commit 9be3074de6
868 changed files with 58698 additions and 2 deletions

View File

@@ -0,0 +1,9 @@
package main
import "fmt"
func main() {
// initialize variables here
fmt.Printf("%v %f %v %q\n", smsSendingLimit, costPerSMS, hasPermission, username)
}

View File

@@ -0,0 +1,11 @@
package main
import "fmt"
func main() {
var smsSendingLimit int
var costPerSMS float64
var hasPermission bool
var username string
fmt.Printf("%v %f %v %q\n", smsSendingLimit, costPerSMS, hasPermission, username)
}

View File

@@ -0,0 +1 @@
0 0.000000 false ""

View File

@@ -0,0 +1,43 @@
# Basic Types
Go's basic variable types are:
```go
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128
```
We talked about `string`s and `int`s previously, and those two types should be fairly self-explanatory. A `bool` is a boolean variable, meaning it has a value of `true` or `false`. The [floating point](https://en.wikipedia.org/wiki/Floating-point_arithmetic) types (`float32` and `float64`) are used for numbers that are not integers -- that is, they have digits to the right of the decimal place, such as `3.14159`. The `float32` type uses 32 bits of precision, while the `float64` type uses 64 bits to be able to more precisely store more digits. Don't worry too much about the intricacies of the other types for now. We will cover some of them in more detail as the course progresses.
# Declaring a variable
Variables are declared using the `var` keyword. For example, to declare a variable called `number` of type `int`, you would write:
```go
var number int
```
To declare a variable called `pi` to be of type `float64` with a value of `3.14159`, you would write:
```go
var pi float64 = 3.14159
```
The value of an initialized variable with no assignment will be its [zero value](https://tour.golang.org/basics/12).
## Initialize some variables
Initialize the given variables to `int`, `float64`, `bool` and `string` respectively, with their zero values.

View File

@@ -0,0 +1,17 @@
package main
import "fmt"
func main() {
messageLen := 10
maxMessageLen := 20
fmt.Println("Trying to send a message of length:", messageLen, "and a max length of:", maxMessageLen)
// don't touch above this line
if messageLen > maxMessageLen {
fmt.Println("Message sent")
} else {
fmt.Println("Message not sent")
}
}

View File

@@ -0,0 +1,17 @@
package main
import "fmt"
func main() {
messageLen := 10
maxMessageLen := 20
fmt.Println("Trying to send a message of length:", messageLen, "and a max length of:", maxMessageLen)
// don't touch above this line
if messageLen <= maxMessageLen {
fmt.Println("Message sent")
} else {
fmt.Println("Message not sent")
}
}

View File

@@ -0,0 +1,2 @@
Trying to send a message of length: 10 and a max length of: 20
Message sent

View File

@@ -0,0 +1,36 @@
# Conditionals
`if` statements in Go don't use parentheses around the condition:
```go
if height > 4 {
fmt.Println("You are tall enough!")
}
```
`else if` and `else` are supported as you would expect:
```go
if height > 6 {
fmt.Println("You are super tall!")
} else if height > 4 {
fmt.Println("You are tall enough!")
} else {
fmt.Println("You are not tall enough!")
}
```
## Assignment
Fix the bug on line `12`. The `if` statement should print "Message sent" if the `messageLen` is *less than or equal to* the `maxMessageLen`, or "Message not sent" otherwise.
### Tips
Here are some of the comparison operators in Go:
* `==` equal to
* `!=` not equal to
* `<` less than
* `>` greater than
* `<=` less than or equal to
* `>=` greater than or equal to

View File

@@ -0,0 +1,8 @@
{
"question": "Why would you use the 'initial' section of an `if` statement?",
"answers": [
"To keep the code concise and the scope limited",
"To speed up my code",
"To confuse other programmers"
]
}

View File

@@ -0,0 +1,29 @@
# The initial statement of an if block
An `if` conditional can have an "initial" statement. The variable(s) created in the initial statement are *only* defined within the scope of the `if` body.
```go
if INITIAL_STATEMENT; CONDITION {
}
```
## Why would I use this?
This is just some syntactic sugar that Go offers to shorten up code in some cases. For example, instead of writing:
```go
length := getLength(email)
if length < 1 {
fmt.Println("Email is invalid")
}
```
We can do:
```go
if length := getLength(email); length < 1 {
fmt.Println("Email is invalid")
}
```
Not only is this code a bit shorter, but it also removes `length` from the parent scope, which is convenient because we don't need it there - we only need access to it while checking a condition.

View File

@@ -0,0 +1,9 @@
package main
import "fmt"
func main() {
// declare here
fmt.Println(congrats)
}

View File

@@ -0,0 +1,10 @@
package main
import "fmt"
func main() {
// declare here
congrats := "happy birthday!"
fmt.Println(congrats)
}

View File

@@ -0,0 +1 @@
happy birthday!

View File

@@ -0,0 +1,30 @@
# Short Variable Declaration
Inside a function (even the main function), the `:=` short assignment statement can be used in place of a `var` declaration. The `:=` operator infers the type of the new variable based on the value.
```go
var empty string
```
Is the same as
```go
empty := ""
```
```go
numCars := 10 // inferred to be an integer
temperature := 0.0 // temperature is inferred to be a floating point value because it has a decimal point
var isFunny = true // isFunny is inferred to be a boolean
```
Outside of a function (in the [global/package scope](https://dave.cheney.net/2017/06/11/go-without-package-scoped-variables)), every statement begins with a keyword (`var`, `func`, and so on) and so the `:=` construct is not available.
## Assignment
A lot of our users send birthday messages using the Textio API.
Declare a variable named `congrats` with the value "happy birthday!" using a short variable declaration.

View File

@@ -0,0 +1,8 @@
package main
import "fmt"
func main() {
penniesPerText := 2
fmt.Printf("The type of penniesPerText is %T\n", penniesPerText)
}

View File

@@ -0,0 +1,8 @@
package main
import "fmt"
func main() {
penniesPerText := 0.02
fmt.Printf("The type of penniesPerText is %T\n", penniesPerText)
}

View File

@@ -0,0 +1 @@
The type of penniesPerText is float64

View File

@@ -0,0 +1,24 @@
# Type Inference
To declare a variable without specifying an explicit type (either by using the `:=` syntax or `var = expression` syntax), the variable's type is *inferred* from the value on the right hand side.
When the right hand side of the declaration is typed, the new variable is of that same type:
```go
var i int
j := i // j is also an int
```
However, when the right hand side is a literal value (an untyped numeric constant like `42` or `3.14`), the new variable will be an `int`, `float64`, or `complex128` depending on its precision:
```go
i := 42 // int
f := 3.14 // float64
g := 0.867 + 0.5i // complex128
```
## Assignment
Our current price to send a text message is 2 cents. However, it's likely that in the future the price will be a fraction of a penny, so we should use a `float64` to store this value.
Edit the `penniesPerText` declaration so that it's inferred by the compiler to be a `float64`.

View File

@@ -0,0 +1,9 @@
package main
import "fmt"
func main() {
// declare here
fmt.Println(averageOpenRate, displayMessage)
}

View File

@@ -0,0 +1,9 @@
package main
import "fmt"
func main() {
// declare here
averageOpenRate, displayMessage := .23, "is the average open rate of your messages"
fmt.Println(averageOpenRate, displayMessage)
}

View File

@@ -0,0 +1 @@
0.23 is the average open rate of your messages

View File

@@ -0,0 +1,17 @@
# Same Line Declarations
We are able to declare multiple variables on the same line:
```go
mileage, company := 80276, "Tesla"
// is the same as
mileage := 80276
company := "Tesla"
```
## Assignment
Within the main function, declare a float called `averageOpenRate` and string called `displayMessage` on the same line.
Initialize them to values of `.23` and `is the average open rate of your messages` respectively before they are printed.

View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
accountAge := 2.6
// create a new "accountAgeInt" here
// it should be the result of casting "accountAge" to an integer
fmt.Println("Your account has existed for", accountAgeInt, "years")
}

View File

@@ -0,0 +1,13 @@
package main
import "fmt"
func main() {
accountAge := 2.6
// create a new "accountAgeInt" here
// it should be the result of casting "accountAge" to an integer
accountAgeInt := int(accountAge)
fmt.Println("Your account has existed for", accountAgeInt, "years")
}

View File

@@ -0,0 +1 @@
Your account has existed for 2 years

View File

@@ -0,0 +1,37 @@
# Type Sizes
Ints, [uints](https://www.cs.utah.edu/~germain/PPS/Topics/unsigned_integer.html#:~:text=Unsigned%20Integers,negative%20(zero%20or%20positive).), [floats](https://techterms.com/definition/floatingpoint), and [complex](https://www.cloudhadoop.com/2018/12/golang-tutorials-complex-types-numbers.html#:~:text=Golang%20Complex%20Type%20Numbers,complex%20number%20is%2012.8i.) numbers all have type sizes.
```go
int int8 int16 int32 int64 // whole numbers
uint uint8 uint16 uint32 uint64 uintptr // positive whole numbers
float32 float64 // decimal numbers
complex64 complex128 // imaginary numbers (rare)
```
The size (8, 16, 32, 64, 128, etc) indicates how many bits in memory will be used to store the variable. The default `int` and `uint` types are just aliases that refer to their respective 32 or 64 bit sizes depending on the environment of the user.
The standard sizes that should be used unless the developer has a specific need are:
* `int`
* `uint`
* `float64`
* `complex128`
Some types can be converted the following way:
```go
temperatureInt := 88
temperatureFloat := float64(temperatureInt)
```
Casting a float to an integer in this way [truncates](https://techterms.com/definition/truncate) the floating point portion.
## Assignment
Our Textio customers want to know how long they have had accounts with us.
Follow the instructions in the comment provided. You will create a new variable called `accountAgeInt` that will be the truncated, integer version of `accountAge`.

View File

@@ -0,0 +1,8 @@
{
"question": "When should you elect to NOT use a 'default type'?",
"answers": [
"When performance and memory are the primary concern",
"When my system has lots of extra hardware I want to utilize",
"When either a 'default' or a specific size will work"
]
}

View File

@@ -0,0 +1,28 @@
# Which Type Should I Use?
With so many types for what is essentially just a number, developers coming from languages that only have one kind of `Number` type (like JavaScript) may find the choices daunting.
## Prefer "default" types
A problem arises when we have a `uint16`, and the function we are trying to pass it into takes an `int`. We're forced to write code riddled with type casts like `int(myUint16)`.
This style of development can be slow and annoying to read. When Go developers stray from the “default” type for any given type family, the code can get messy quickly.
Unless you have a good reason to, stick to the following types:
* `bool`
* `string`
* `int`
* `uint32`
* `byte`
* `rune`
* `float64`
* `complex128`
## When should I use a more specific type?
When you're super concerned about performance and memory usage.
Thats about it. The only reason to deviate from the defaults is to squeeze out every last bit of performance when you are writing an application that is resource-constrained. (Or, in the special case of `uint64`, you need an absurd range of unsigned integers).
You can [read more on this subject here](https://blog.boot.dev/golang/default-native-types-golang/) if you'd like, but it's not required.

View File

@@ -0,0 +1,8 @@
{
"question": "What does the size of a type indicate?",
"answers": [
"Bits",
"Bytes",
"Nibbles"
]
}

View File

@@ -0,0 +1,28 @@
# Which Type Should I Use?
With so many types for what is essentially just a number, developers coming from languages that only have one kind of `Number` type (like JavaScript) may find the choices daunting.
## Prefer "default" types
A problem arises when we have a `uint16`, and the function we are trying to pass it into takes an `int`. We're forced to write code riddled with type casts like `int(myUint16)`.
This style of development can be slow and annoying to read. When Go developers stray from the “default” type for any given type family, the code can get messy quickly.
Unless you have a good reason to, stick to the following types:
* `bool`
* `string`
* `int`
* `uint32`
* `byte`
* `rune`
* `float64`
* `complex128`
## When should I use a more specific type?
When you're super concerned about performance and memory usage.
Thats about it. The only reason to deviate from the defaults is to squeeze out every last bit of performance when you are writing an application that is resource-constrained. (Or, in the special case of `uint64`, you need an absurd range of unsigned integers).
You can [read more on this subject here](https://blog.boot.dev/golang/default-native-types-golang/) if you'd like, but it's not required.

View File

@@ -0,0 +1,13 @@
package main
import "fmt"
func main() {
const premiumPlanName = "Premium Plan"
premiumPlanName = "Basic Plan"
// don't edit below this line
fmt.Println("plan:", premiumPlanName)
fmt.Println("plan:", basicPlanName)
}

View File

@@ -0,0 +1,13 @@
package main
import "fmt"
func main() {
const premiumPlanName = "Premium Plan"
const basicPlanName = "Basic Plan"
// don't edit below this line
fmt.Println("plan:", premiumPlanName)
fmt.Println("plan:", basicPlanName)
}

View File

@@ -0,0 +1,2 @@
plan: Premium Plan
plan: Basic Plan

View File

@@ -0,0 +1,13 @@
# Constants
Constants are declared like variables but use the `const` keyword. Constants can't use the `:=` short declaration syntax.
Constants can be character, string, boolean, or numeric values. They *can not* be more complex types like slices, maps and structs, which are types we will explain later.
As the name implies, the value of a constant can't be changed after it has been declared.
## Use two separate constants
Something weird is happening in this code.
What *should* be happening is that we create 2 separate constants: `premiumPlanName` and `basicPlanName`. Right now it looks like we're trying to overwrite one of them.

View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
const secondsInMinute = 60
const minutesInHour = 60
const secondsInHour = // ?
// don't edit below this line
fmt.Println("number of seconds in an hour:", secondsInHour)
}

View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
const secondsInMinute = 60
const minutesInHour = 60
const secondsInHour = secondsInMinute * minutesInHour
// don't edit below this line
fmt.Println("number of seconds in an hour:", secondsInHour)
}

View File

@@ -0,0 +1 @@
number of seconds in an hour: 3600

View File

@@ -0,0 +1,25 @@
# Computed Constants
Constants must be known at compile time. More often than not they will be declared with a static value:
```go
const myInt = 15
```
However, constants *can be computed* so long as the computation can happen at *compile time*.
For example, this is valid:
```go
const firstName = "Lane"
const lastName = "Wagner"
const fullName = firstName + " " + lastName
```
That said, you *cannot* declare a constant that can only be computed at run-time.
## Assignment
Keeping track of time in a message-sending application is *critical*. Imagine getting an appointment reminder an hour **after** your doctor's visit.
Complete the code using a computed constant to print the number of seconds in an hour.

View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
const name = "Saul Goodman"
const openRate = 30.5
// ?
// don't edit below this line
fmt.Println(msg)
}

View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
const name = "Saul Goodman"
const openRate = 30.5
msg := fmt.Sprintf("Hi %s, your open rate is %.1f percent", name, openRate)
// don't edit below this line
fmt.Println(msg)
}

View File

@@ -0,0 +1 @@
Hi Saul Goodman, your open rate is 30.5 percent

View File

@@ -0,0 +1,57 @@
# Formatting Strings in Go
Go follows the [printf tradition](https://cplusplus.com/reference/cstdio/printf/) from the C language. In my opinion, string formatting/interpolation in Go is currently *less* elegant than JavaScript and Python.
* [fmt.Printf](https://pkg.go.dev/fmt#Printf) - Prints a formatted string to [standard out](https://stackoverflow.com/questions/3385201/confused-about-stdin-stdout-and-stderr).
* [fmt.Sprintf()](https://pkg.go.dev/fmt#Sprintf) - Returns the formatted string
## Examples
### %v - Interpolate the default representation
The `%v` variant prints the Go syntax representation of a value. You can usually use this if you're unsure what else to use. That said, it's better to use the type-specific variant if you can.
```go
fmt.Printf("I am %v years old", 10)
// I am 10 years old
fmt.Printf("I am %v years old", "way too many")
// I am way too many years old
```
### `%s` - Interpolate a string
```go
fmt.Printf("I am %s years old", "way too many")
// I am way too many years old
```
### `%d` - Interpolate an integer in decimal form
```go
fmt.Printf("I am %d years old", 10)
// I am 10 years old
```
### `%f` - Interpolate a decimal
```go
fmt.Printf("I am %f years old", 10.523)
// I am 10.523000 years old
// The ".2" rounds the number to 2 decimal places
fmt.Printf("I am %.2f years old", 10.523)
// I am 10.53 years old
```
If you're interested in all the formatting options, feel free to take a look at the `fmt` package's [docs here](https://pkg.go.dev/fmt#hdr-Printing).
## Assignment
Create a new variable called `msg` on line 9. It's a string that contains the following:
```
Hi NAME, your open rate is OPENRATE percent
```
Where `NAME` is the given `name`, and `OPENRATE` is the `openRate` rounded to the nearest "tenths" place.