1
0
Fork 0

Compare commits

..

No commits in common. "e17734dab43c8963172390fc3765212ec3eb5102" and "96daf2f7e27e67b1710aab4fc4777a2db56c836b" have entirely different histories.

8 changed files with 102 additions and 207 deletions

View File

@ -1,3 +1,3 @@
module gitty.informatik.th-mannheim.de/steger/pr3-ws202526/go/00-hello-world/hello-world module gitty.informatik.th-mannheim.de/steger/pr3-sose2026/go/00-hello-world/hello-world
go 1.26.0 go 1.26.0

View File

@ -13,23 +13,33 @@ func main() {
exit = "exit" exit = "exit"
) )
//TODO: implement according to README.md
fmt.Println("Welcome to the Simple Calculator!") fmt.Println("Welcome to the Simple Calculator!")
for { for {
var operation string var operation string
fmt.Print("\nEnter operation (add, subtract, multiply, divide, exit): ") fmt.Print("\nEnter operation (add, subtract, multiply, divide, exit): ")
fmt.Scan(&operation) fmt.Scan(&operation)
//the following code just demonstrates how to use fmt.Scan
if operation == exit { if operation == exit {
fmt.Println("Goodbye!") fmt.Println("Goodbye!")
break break
} }
var str string
fmt.Print("Please enter a string: ")
fmt.Scan(&str)
var num1, num2 float64 var num1, num2 float64
fmt.Print("Enter the first number: ") fmt.Print("Enter the first number: ")
fmt.Scan(&num1) fmt.Scan(&num1)
fmt.Print("Enter the second number: ") fmt.Print("Enter the second number: ")
fmt.Scan(&num2) fmt.Scan(&num2)
var x float64
fmt.Print("Please enter a float: ")
fmt.Scan(&x)
fmt.Printf("You entered '%s' and %f\n", str, x)
switch operation { switch operation {
case add: case add:
fmt.Printf("Result: %.2f\n", num1+num2) fmt.Printf("Result: %.2f\n", num1+num2)

View File

@ -1,20 +1,15 @@
package main package main
import ( import "fmt"
"fmt"
)
// a new type named Category that can hold integer values
type Category int type Category int
// The go equivalent of an enum that enumerates different named Categories
const ( const (
Electronics Category = iota //0 Electronics Category = iota
Groceries //1 Groceries
Clothes //2 Clothes
) )
// implementation of the fmt.Stringer interface. In that way, Categories can be printed using the fmt.Print* functions
func (c Category) String() string { func (c Category) String() string {
switch c { switch c {
case Electronics: case Electronics:
@ -28,93 +23,99 @@ func (c Category) String() string {
} }
} }
// Struct for product details
type Product struct { type Product struct {
Name string Name string
Price float64 Price float64
Quantity int Quantity int
Category string //TODO: use enum instead
Category Category Category Category
} }
// implementation of the fmt.Stringer interface for printing products func addProduct(inventory *[]Product, name string, price float64, quantity int, category string) {
func (p Product) String() string { //TODO: implement
return fmt.Sprintf("%s (%s, Price: $%.2f, Quantity: %d)", p.Name, p.Category, p.Price, p.Quantity) // Add a new product to the inventory
} func addProduct(inventory *[]Product, name string, price float64, quantity int, category Category) {
// Check if the product already exists in the inventory
func addProduct(inventory map[string]Product, name string, price float64, quantity int, category Category) { for _, product := range *inventory {
if product.Name == name {
//do not create a new product in case a product with the name already exists fmt.Println("Product already exists.")
if _, exists := inventory[name]; exists { return
fmt.Printf("Unable to add new Product %s: Product already exists.\n", name) }
return
} }
// Add the new product
//create a new product... *inventory = append(*inventory, Product{
p := Product{name, price, quantity, category} Name: name,
inventory[name] = p // ...and insert it into the map Price: price,
Quantity: quantity,
Category: category,
})
fmt.Printf("Added product: %s\n", name)
} }
func removeProduct(inventory map[string]Product, name string) { // Remove a product from the inventory
//no checks required. Does nothing if the product doesn't exist. func removeProduct(inventory *[]Product, name string) {
delete(inventory, name) //TODO: implement
for i, product := range *inventory {
if product.Name == name {
*inventory = append((*inventory)[:i], (*inventory)[i+1:]...)
fmt.Printf("Removed product: %s\n", name)
return
}
}
fmt.Println("Product not found.")
} }
func updateQuantity(inventory map[string]Product, name string, newQuantity int) { // Update the quantity of a product
p := inventory[name] //read from the map func updateQuantity(inventory *[]Product, name string, newQuantity int) {
p.Quantity = newQuantity //update value //TODO: implement
inventory[name] = p //store back into the map for i, product := range *inventory {
if product.Name == name {
(*inventory)[i].Quantity = newQuantity
fmt.Printf("Updated quantity for %s: New Quantity = %d\n", name, newQuantity)
return
}
}
fmt.Println("Product not found.")
} }
func displayInventory(inventory map[string]Product) { // Display the inventory
//Iterate over the inventory func displayInventory(inventory []Product) {
i := 1 //TODO: implement
for _, p := range inventory { //don't care about the key (_), only the value (p) is relevant fmt.Println("Inventory:")
fmt.Printf("%d. %s\n", i, p) for _, product := range inventory {
i++ fmt.Printf("%s - %s (Price: $%.2f, Quantity: %d)\n",
product.Name, product.Category, product.Price, product.Quantity)
} }
} }
func main() { func main() {
// Initialize inventory
fmt.Println("Welcome to the Inventory Manager!") inventory := []Product{
{Name: "Laptop", Price: 1000, Quantity: 5, Category: "Electronics"},
// Store a fixed list of initial product names in an array. {Name: "Apples", Price: 2, Quantity: 50, Category: "Groceries"},
initialProductNames := [...]string{"Laptop"} {Name: "T-shirt", Price: 10, Quantity: 20, Category: "Clothes"},
{Name: "Laptop", Price: 1000, Quantity: 5, Category: Electronics},
// Convert the array into a slice so the inventory can grow or shrink dynamically. {Name: "Apples", Price: 2, Quantity: 50, Category: Groceries},
productNames := initialProductNames[:] {Name: "T-shirt", Price: 10, Quantity: 20, Category: Clothes},
productNames = append(productNames, "Apples", "T-shirt")
// Use a map to associate product names with details like quantity, price, and category.
prices := []float64{1000.0, 2.0, 10.0}
quantities := []int{5, 50, 20}
categories := []Category{Electronics, Groceries, Clothes}
inventory := make(map[string]Product)
for i, name := range productNames {
inventory[name] = Product{name, prices[i], quantities[i], categories[i]}
} }
// Display initial inventory // Display initial inventory
fmt.Println("\nInitial Inventory:")
displayInventory(inventory) displayInventory(inventory)
// Add a new product // Add a new product
fmt.Println("\nAdding a new product: Phone (Electronics, Price: $800, Quantity: 10)") addProduct(&inventory, "Phone", 800, 10, "Electronics")
addProduct(inventory, "Phone", 800, 10, Electronics) addProduct(&inventory, "Phone", 800, 10, Electronics)
// Display updated inventory // Display updated inventory
fmt.Println("\nUpdated Inventory:")
displayInventory(inventory) displayInventory(inventory)
// Update the quantity of an existing product // Update the quantity of an existing product
fmt.Println("\nUpdating quantity for Apples: New Quantity = 30") updateQuantity(&inventory, "Apples", 30)
updateQuantity(inventory, "Apples", 30)
// Remove a product // Remove a product
fmt.Println("\nRemoving product: T-shirt") removeProduct(&inventory, "T-shirt")
removeProduct(inventory, "T-shirt")
// Display final inventory // Display final inventory
fmt.Println("\nFinal Inventory:")
displayInventory(inventory) displayInventory(inventory)
} }

View File

@ -1,26 +0,0 @@
package main
import "fmt"
type Counter struct {
value int
}
// pointer receiver. The method operates directly on the object c points to
// Use a pointer receiver whenever the object needs to be modified.
func (c *Counter) Increment() {
c.value++
}
// value receiver. The method operates on copy of object c. Use a value
// receiver when the object does not need to be modified in the method.
func (c Counter) String() string {
return fmt.Sprintf("Counter value: %d", c.value)
}
func main() {
c := Counter{}
fmt.Println(c)
c.Increment()
fmt.Println(c)
}

View File

@ -1,66 +0,0 @@
package main
import (
"fmt"
"math"
)
type geometry interface {
area() float64
perim() float64
}
type rect struct {
width, height float64
}
// Ensure that rect implements the geometry interface
var _ geometry = rect{}
type circle struct {
radius float64
}
// Ensure that circle implements the geometry interface
var _ geometry = circle{}
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
}
//Metods demonstrates how to use an interface
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}
//Method demonstrates casting an interface to a concrete type.
//Should be avoided in practice whenever possible.
func detectCircle(g geometry) {
if c, ok := g.(circle); ok {
fmt.Println("circle with radius", c.radius)
}
}
func main() {
r := rect{width: 3, height: 4}
c := circle{radius: 5}
measure(r)
measure(c)
detectCircle(r)
detectCircle(c)
}

View File

@ -11,12 +11,12 @@ func (p Person) Say() {
} }
type Student struct { type Student struct {
Person //struct Person is embedded Person //struct Person is embedded
Semester int Semester int
} }
type Teacher struct { type Teacher struct {
Person //struct Person is embedded Person //struct Person is embedded
Subject string Subject string
} }

View File

@ -2,10 +2,7 @@ package main
import "fmt" import "fmt"
// a generic function that takes a slice of any type and a value of that type, and returns the index of the value in the slice, or -1 if it is not found. func SlicesIndex[S []E, E int](s []string, v string) int {
// The type parameters S and E are declared in square brackets before the function name, and they can be used in the function signature and body.
// The constraint comparable means that the type E must support the == operator, which is necessary for comparing the value with the elements of the slice.
func SlicesIndex[S []E, E comparable](s S, v E) int {
for i := range s { for i := range s {
if v == s[i] { if v == s[i] {
return i return i
@ -14,34 +11,27 @@ func SlicesIndex[S []E, E comparable](s S, v E) int {
return -1 return -1
} }
// represents a linked list of any type T. The type parameter T is used in the definition of List and its methods, type List struct {
// and it can be instantiated with any type when we create a List value. The type any is in fact defined as head, tail *element
// an empty interface. Thanks to duck-typing it can be used to represent any type, but it does not provide any
// operations on the values of that type.
type List[T any] struct {
head, tail *element[T]
} }
// the generic element of the linked list type element struct {
type element[T any] struct { next *element
next *element[T] val int
val T
} }
// adds an instance of the generic type to the list func (lst *List) Push(v int) {
func (lst *List[T]) Push(v T) {
if lst.tail == nil { if lst.tail == nil {
lst.head = &element[T]{val: v} lst.head = &element{val: v}
lst.tail = lst.head lst.tail = lst.head
} else { } else {
lst.tail.next = &element[T]{val: v} lst.tail.next = &element{val: v}
lst.tail = lst.tail.next lst.tail = lst.tail.next
} }
} }
// returns all elements of the list as a slice of the generic type. func (lst *List) AllElements() []int {
func (lst List[T]) AllElements() []T { var elems []int
var elems []T
for e := lst.head; e != nil; e = e.next { for e := lst.head; e != nil; e = e.next {
elems = append(elems, e.val) elems = append(elems, e.val)
} }
@ -49,21 +39,13 @@ func (lst List[T]) AllElements() []T {
} }
func main() { func main() {
var s = []string{"foo", "bar", "zoo"} var s = []string{"foo", "bar", "zoo"}
// The types S and E are explicitly specified as []string and string respectively.
fmt.Println("index of zoo:", SlicesIndex[[]string, string](s, "zoo"))
var s2 = []int{2, 4, 5, 6} fmt.Println("index of zoo:", SlicesIndex(s, "zoo"))
// The type E is inferred from the type of the value 4, which is int,
// and the type S is inferred from the type of the slice s2, which is []int.
fmt.Println("index of 4: ", SlicesIndex(s2, 4))
// instantiate a list of float64 elements lst := List{}
lst := List[float64]{}
lst.Push(10) lst.Push(10)
lst.Push(13) lst.Push(13)
lst.Push(23) lst.Push(23)
lst.Push(23.3)
fmt.Println("list:", lst.AllElements()) fmt.Println("list:", lst.AllElements())
} }

View File

@ -6,22 +6,18 @@ import (
) )
func main() { func main() {
f := createFile("/tmp/defer.txt")
writeFile(f)
closeFile(f)
}
func createFile(p string) *os.File {
fmt.Println("creating") fmt.Println("creating")
f, err := os.Create("/tmp/defer.txt") f, err := os.Create(p)
// defer the closing of the file until the surrounding function returns.
// This ensures that the file will be closed even if there is a panic or an early return in the function.
defer closeFile(f)
if err != nil { if err != nil {
panic(err) panic(err)
} }
return f
//will not be called in case of a panic before
writeFile(f)
// closeFile will be called here due to the defer-statement, even in case of a panic before.
} }
func writeFile(f *os.File) { func writeFile(f *os.File) {
@ -31,10 +27,8 @@ func writeFile(f *os.File) {
func closeFile(f *os.File) { func closeFile(f *os.File) {
fmt.Println("closing") fmt.Println("closing")
var err error err := f.Close()
if f != nil {
err = f.Close()
}
if err != nil { if err != nil {
panic(err) panic(err)
} }