Решение на Concurrent Tasks от Станислав Гатев

Обратно към всички решения

Към профила на Станислав Гатев

Резултати

  • 10 точки от тестове
  • 1 бонус точка
  • 11 точки общо
  • 10 успешни тест(а)
  • 0 неуспешни тест(а)

Код

package main
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"sync"
)
type Library interface {
// Добавя книга от json
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Aко са повече от 4 - връща грешка
AddBookJSON(data []byte) (int, error)
// Добавя книга от xml
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Ако са повече от 4 - връщаме грешка
AddBookXML(data []byte) (int, error)
// Ангажира свободен "библиотекар" да ни обработва заявките.
// Библиотекарите са фиксиран брой - подават се като параметър на NewLibrary
// Блокира ако всички библиотекари са заети.
// Връщат се два канала:
// първият е само за писане - по него ще изпращаме заявките
// вторият е само за четене - по него ще получаваме отговорите.
// Ако затворим канала със заявките - освобождаваме библиотекаря.
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type LibraryRequest interface {
// Тип на заявката:
// 1 - Borrow book
// 2 - Return book
// 3 - Get availability information about book
GetType() int
// Връща isbn на книгата, за която се отнася Request-a
GetISBN() string
}
type LibraryResponse interface {
// Ако книгата съществува/налична е - обект имплементиращ Stringer (повече информация по-долу)
// Aко книгата не съществува първият резултат е nil.
// Връща се и подобаващa грешка (виж по-долу) - ако такава е възникнала.
// Когато се е резултат на заявка от тип 2 (Return book) - не е нужно да я закачаме към отговора.
GetBook() (fmt.Stringer, error)
// available - Колко наличности от книгата имаме останали след изпълнението на заявката.
// Тоест, ако сме имали 3 копия от Х и това е отговор на Take заявка - тук ще има 2.
// registered - Колко копия от тази книга има регистрирани в библиотеката (макс 4).
GetAvailability() (available int, registered int)
}
// Author is a representation of a book author.
type Author struct {
FirstName string `json:"first_name" xml:"first_name"`
LastName string `json:"last_name" xml:"last_name"`
}
// String returns a string representation of the author.
func (a *Author) String() string {
return a.FirstName + " " + a.LastName
}
// Book is a representation of a book.
type Book struct {
ISBN string `json:"isbn" xml:"isbn,attr"`
Title string `json:"title" xml:"title"`
Author *Author `json:"author" xml:"author"`
Ratings []int `json:"ratings" xml:"ratings"`
sync.Mutex
limit int
registered int
borrowed int
}
// Register increments the number of copies of this book in the library.
func (b *Book) Register() error {
b.Lock()
defer b.Unlock()
if b.registered < b.limit {
b.registered++
return nil
} else {
return errors.New("Има 4 копия на книга " + b.ISBN)
}
}
// Borrow decrements the number of available copies of this book in the library.
func (b *Book) Borrow() error {
b.Lock()
defer b.Unlock()
var err error
if b.borrowed < b.registered {
b.borrowed++
} else {
err = errors.New("Няма наличност на книга " + b.ISBN)
}
return err
}
// Return increments the number of available copies of this book in the library.
func (b *Book) Return() error {
b.Lock()
defer b.Unlock()
var err error
if b.borrowed > 0 {
b.borrowed--
} else {
err = errors.New("Всички копия са налични " + b.ISBN)
}
return err
}
// Available returns the number of available copies of this book in the library.
func (b *Book) Available() int {
b.Lock()
defer b.Unlock()
return b.registered - b.borrowed
}
// String returns a string representation of the book.
func (b *Book) String() string {
return "[" + b.ISBN + "] " + b.Title + " от " + b.Author.String()
}
// ChannelLibraryResponse is a representation of a response to a library request.
type ChannelLibraryResponse struct {
book *Book
err error
registered int
available int
}
// GetBook returns the target book of the library request and error if any occurs.
func (mr *ChannelLibraryResponse) GetBook() (fmt.Stringer, error) {
return mr.book, mr.err
}
// GetAvailability returns the available and registered copies of the target book.
func (mr *ChannelLibraryResponse) GetAvailability() (available int, registered int) {
return mr.available, mr.registered
}
// ChannelLibrary implements a library with librarians operating over a buffered channel.
type ChannelLibrary struct {
sync.Mutex
books map[string]*Book
librarians chan<- func()
}
// AddBook registers a book copy in the library.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBook(book *Book) (int, error) {
cl.Lock()
defer cl.Unlock()
if b, ok := cl.books[book.ISBN]; ok {
book = b
} else {
book.limit = 4
cl.books[book.ISBN] = book
}
err := book.Register()
return book.registered, err
}
// AddBookJSON registers a book copy in the library from its JSON representation.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBookJSON(data []byte) (int, error) {
var book Book
json.Unmarshal(data, &book)
return cl.AddBook(&book)
}
// AddBookXML registers a book copy in the library from its XML representation.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBookXML(data []byte) (int, error) {
var book Book
xml.Unmarshal(data, &book)
return cl.AddBook(&book)
}
// GetBook returns a book from the library by its ISBN number and error if any occurs.
func (cl *ChannelLibrary) GetBook(isbn string) (*Book, error) {
cl.Lock()
defer cl.Unlock()
book, ok := cl.books[isbn]
if ok {
return book, nil
} else {
return nil, errors.New("Непозната книга " + isbn)
}
}
// Hello initiates communication with a librarian. Blocks if no librarian is free.
// Returns requests and responses channels that are used for the communication.
func (cl *ChannelLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
requests := make(chan LibraryRequest)
responses := make(chan LibraryResponse)
cl.librarians <- func() {
for request := range requests {
book, err := cl.GetBook(request.GetISBN())
var registered, available int
if err == nil {
switch request.GetType() {
case 1:
err = book.Borrow()
case 2:
err = book.Return()
case 3:
}
registered = book.registered
available = book.Available()
}
responses <- &ChannelLibraryResponse{book, err, registered, available}
}
close(responses)
}
return requests, responses
}
// NewLibrary initializes a new ChannelLibrary with specific number of librarians.
func NewLibrary(librariansCount int) Library {
librarians := make(chan func())
for i := 0; i < librariansCount; i++ {
go func() {
for handleRequest := range librarians {
handleRequest()
}
}()
}
return &ChannelLibrary{
books: map[string]*Book{},
librarians: librarians,
}
}

Лог от изпълнението

PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.003s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.004s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.004s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.004s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.004s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.004s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.004s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.003s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.004s
PASS
ok  	_/tmp/d20151207-5667-1ludm8	0.003s

История (4 версии и 3 коментара)

Станислав обнови решението на 30.11.2015 00:28 (преди над 2 години)

+package main
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "sync"
+)
+
+type Library interface {
+
+ // Добавя книга от json
+ // Oтговаря с общия брой копия в библиотеката (не само наличните).
+ // Aко са повече от 4 - връща грешка
+ AddBookJSON(data []byte) (int, error)
+
+ // Добавя книга от xml
+ // Oтговаря с общия брой копия в библиотеката (не само наличните).
+ // Ако са повече от 4 - връщаме грешка
+ AddBookXML(data []byte) (int, error)
+
+ // Ангажира свободен "библиотекар" да ни обработва заявките.
+ // Библиотекарите са фиксиран брой - подават се като параметър на NewLibrary
+ // Блокира ако всички библиотекари са заети.
+ // Връщат се два канала:
+ // първият е само за писане - по него ще изпращаме заявките
+ // вторият е само за четене - по него ще получаваме отговорите.
+ // Ако затворим канала със заявките - освобождаваме библиотекаря.
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryRequest interface {
+ // Тип на заявката:
+ // 1 - Borrow book
+ // 2 - Return book
+ // 3 - Get availability information about book
+ GetType() int
+
+ // Връща isbn на книгата, за която се отнася Request-a
+ GetISBN() string
+}
+
+type LibraryResponse interface {
+ // Ако книгата съществува/налична е - обект имплементиращ Stringer (повече информация по-долу)
+ // Aко книгата не съществува първият резултат е nil.
+ // Връща се и подобаващa грешка (виж по-долу) - ако такава е възникнала.
+ // Когато се е резултат на заявка от тип 2 (Return book) - не е нужно да я закачаме към отговора.
+ GetBook() (fmt.Stringer, error)
+
+ // available - Колко наличности от книгата имаме останали след изпълнението на заявката.
+ // Тоест, ако сме имали 3 копия от Х и това е отговор на Take заявка - тук ще има 2.
+ // registered - Колко копия от тази книга има регистрирани в библиотеката (макс 4).
+ GetAvailability() (available int, registered int)
+}
+
+// Author is a representation of a book author.
+type Author struct {
+ FirstName string `json:"first_name" xml:"first_name"`
+ LastName string `json:"last_name" xml:"last_name"`
+}
+
+// String returns a string representation of the author.
+func (a *Author) String() string {
+ return a.FirstName + " " + a.LastName
+}
+
+// Book is a representation of a book.
+type Book struct {
+ ISBN string `json:"isbn" xml:"isbn"`
+ Title string `json:"title" xml:"title"`
+ Author *Author `json:"author" xml:"author"`
+ Ratings []int `json:"ratings" xml:"ratings"`
+
+ sync.Mutex
+ limit int
+ registered int
+ borrowed int
+}
+
+// Register increments the number of copies of this book in the library.
+func (b *Book) Register() {
+ b.Lock()
+ defer b.Unlock()
+
+ if b.registered < b.limit {
+ b.registered++
+ }
+}
+
+// Borrow decrements the number of available copies of this book in the library.
+func (b *Book) Borrow() error {
+ b.Lock()
+ defer b.Unlock()
+
+ var err error
+ if b.borrowed < b.registered {
+ b.borrowed++
+ } else {
+ err = errors.New("Няма наличност на книга " + b.ISBN)
+ }
+ return err
+}
+
+// Return increments the number of available copies of this book in the library.
+func (b *Book) Return() error {
+ b.Lock()
+ defer b.Unlock()
+
+ var err error
+ if b.borrowed > 0 {
+ b.borrowed--
+ } else {
+ err = errors.New("Всички копия са налични " + b.ISBN)
+ }
+ return err
+}
+
+// Registered returns the number of registered copies of this book in the library.
+func (b *Book) Registered() (int, error) {
+ b.Lock()
+ defer b.Unlock()
+
+ total := b.registered
+ if total < b.limit {
+ return total, nil
+ } else {
+ return total, errors.New("Има 4 копия на книга " + b.ISBN)
+ }
+}
+
+// Available returns the number of available copies of this book in the library.
+func (b *Book) Available() int {
+ b.Lock()
+ defer b.Unlock()
+
+ return b.registered - b.borrowed
+}
+
+// String returns a string representation of the book.
+func (b *Book) String() string {
+ return "[" + b.ISBN + "] " + b.Title + " от " + b.Author.String()
+}
+
+// ChannelLibraryResponse is a representation of a response to a library request.
+type ChannelLibraryResponse struct {
+ book *Book
+ err error
+ registered int
+ available int
+}
+
+// GetBook returns the target book of the library request and error if any occurs.
+func (mr *ChannelLibraryResponse) GetBook() (fmt.Stringer, error) {
+ return mr.book, mr.err
+}
+
+// GetAvailability returns the available and registered copies of the target book.
+func (mr *ChannelLibraryResponse) GetAvailability() (available int, registered int) {
+ return mr.available, mr.registered
+}
+
+// ChannelLibrary implements a library with librarians operating over a buffered channel.
+type ChannelLibrary struct {
+ books map[string]*Book
+
+ sync.Mutex
+ librarians chan<- func()
+}
+
+// AddBook registers a book copy in the library.
+// Returns the number of registered copies of the book and error if any occurs.
+func (cl *ChannelLibrary) AddBook(book *Book) (int, error) {
+ cl.Lock()
+ defer cl.Unlock()
+
+ if b, ok := cl.books[book.ISBN]; ok {
+ book = b
+ } else {
+ book.limit = 4
+ cl.books[book.ISBN] = book
+ }
+
+ book.Register()
+ return book.Registered()
+}
+
+// AddBookJSON registers a book copy in the library from its JSON representation.
+// Returns the number of registered copies of the book and error if any occurs.
+func (cl *ChannelLibrary) AddBookJSON(data []byte) (int, error) {
+ var book Book
+ json.Unmarshal(data, &book)
+ return cl.AddBook(&book)
+}
+
+// AddBookXML registers a book copy in the library from its XML representation.
+// Returns the number of registered copies of the book and error if any occurs.
+func (cl *ChannelLibrary) AddBookXML(data []byte) (int, error) {
+ var book Book
+ xml.Unmarshal(data, &book)
+ return cl.AddBook(&book)
+}
+
+// GetBook returns a book from the library by its ISBN number and error if any occurs.
+func (cl *ChannelLibrary) GetBook(isbn string) (*Book, error) {
+ cl.Lock()
+ defer cl.Unlock()
+
+ book, ok := cl.books[isbn]
+ if ok {
+ return book, nil
+ } else {
+ return nil, errors.New("Непозната книга " + isbn)
+ }
+}
+
+// Hello initiates communication with a librarian. Blocks if no librarian is free.
+// Returns requests and responses channels that are used for the communication.
+func (cl *ChannelLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ requests := make(chan LibraryRequest)
+ responses := make(chan LibraryResponse)
+
+ cl.librarians <- func() {
+ for request := range requests {
+ book, err := cl.GetBook(request.GetISBN())
+ var registered, available int
+
+ if err == nil {
+ switch request.GetType() {
+ case 1:
+ err = book.Borrow()
+ case 2:
+ err = book.Return()
+ case 3:
+ }
+ registered, _ = book.Registered()
+ available = book.Available()
+ }
+ responses <- &ChannelLibraryResponse{book, err, registered, available}
+ }
+ }
+
+ return requests, responses
+}
+
+// NewLibrary initializes a new ChannelLibrary with specific number of librarians.
+func NewLibrary(librariansCount int) Library {
+ librarians := make(chan func(), librariansCount)
+
+ go func() {
+ for work := range librarians {
+ work()
+ }
+ }()
+
+ return &ChannelLibrary{
+ books: map[string]*Book{},
+ librarians: librarians,
+ }
+}

Станислав обнови решението на 30.11.2015 11:02 (преди над 2 години)

package main
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"sync"
)
type Library interface {
// Добавя книга от json
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Aко са повече от 4 - връща грешка
AddBookJSON(data []byte) (int, error)
// Добавя книга от xml
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Ако са повече от 4 - връщаме грешка
AddBookXML(data []byte) (int, error)
// Ангажира свободен "библиотекар" да ни обработва заявките.
// Библиотекарите са фиксиран брой - подават се като параметър на NewLibrary
// Блокира ако всички библиотекари са заети.
// Връщат се два канала:
// първият е само за писане - по него ще изпращаме заявките
// вторият е само за четене - по него ще получаваме отговорите.
// Ако затворим канала със заявките - освобождаваме библиотекаря.
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type LibraryRequest interface {
// Тип на заявката:
// 1 - Borrow book
// 2 - Return book
// 3 - Get availability information about book
GetType() int
// Връща isbn на книгата, за която се отнася Request-a
GetISBN() string
}
type LibraryResponse interface {
// Ако книгата съществува/налична е - обект имплементиращ Stringer (повече информация по-долу)
// Aко книгата не съществува първият резултат е nil.
// Връща се и подобаващa грешка (виж по-долу) - ако такава е възникнала.
// Когато се е резултат на заявка от тип 2 (Return book) - не е нужно да я закачаме към отговора.
GetBook() (fmt.Stringer, error)
// available - Колко наличности от книгата имаме останали след изпълнението на заявката.
// Тоест, ако сме имали 3 копия от Х и това е отговор на Take заявка - тук ще има 2.
// registered - Колко копия от тази книга има регистрирани в библиотеката (макс 4).
GetAvailability() (available int, registered int)
}
// Author is a representation of a book author.
type Author struct {
FirstName string `json:"first_name" xml:"first_name"`
LastName string `json:"last_name" xml:"last_name"`
}
// String returns a string representation of the author.
func (a *Author) String() string {
return a.FirstName + " " + a.LastName
}
// Book is a representation of a book.
type Book struct {
ISBN string `json:"isbn" xml:"isbn"`
Title string `json:"title" xml:"title"`
Author *Author `json:"author" xml:"author"`
Ratings []int `json:"ratings" xml:"ratings"`
sync.Mutex
limit int
registered int
borrowed int
}
// Register increments the number of copies of this book in the library.
func (b *Book) Register() {
b.Lock()
defer b.Unlock()
if b.registered < b.limit {
b.registered++
}
}
// Borrow decrements the number of available copies of this book in the library.
func (b *Book) Borrow() error {
b.Lock()
defer b.Unlock()
var err error
if b.borrowed < b.registered {
b.borrowed++
} else {
err = errors.New("Няма наличност на книга " + b.ISBN)
}
return err
}
// Return increments the number of available copies of this book in the library.
func (b *Book) Return() error {
b.Lock()
defer b.Unlock()
var err error
if b.borrowed > 0 {
b.borrowed--
} else {
err = errors.New("Всички копия са налични " + b.ISBN)
}
return err
}
// Registered returns the number of registered copies of this book in the library.
func (b *Book) Registered() (int, error) {
b.Lock()
defer b.Unlock()
total := b.registered
if total < b.limit {
return total, nil
} else {
return total, errors.New("Има 4 копия на книга " + b.ISBN)
}
}
// Available returns the number of available copies of this book in the library.
func (b *Book) Available() int {
b.Lock()
defer b.Unlock()
return b.registered - b.borrowed
}
// String returns a string representation of the book.
func (b *Book) String() string {
return "[" + b.ISBN + "] " + b.Title + " от " + b.Author.String()
}
// ChannelLibraryResponse is a representation of a response to a library request.
type ChannelLibraryResponse struct {
book *Book
err error
registered int
available int
}
// GetBook returns the target book of the library request and error if any occurs.
func (mr *ChannelLibraryResponse) GetBook() (fmt.Stringer, error) {
return mr.book, mr.err
}
// GetAvailability returns the available and registered copies of the target book.
func (mr *ChannelLibraryResponse) GetAvailability() (available int, registered int) {
return mr.available, mr.registered
}
// ChannelLibrary implements a library with librarians operating over a buffered channel.
type ChannelLibrary struct {
- books map[string]*Book
-
sync.Mutex
+
+ books map[string]*Book
librarians chan<- func()
}
// AddBook registers a book copy in the library.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBook(book *Book) (int, error) {
cl.Lock()
defer cl.Unlock()
if b, ok := cl.books[book.ISBN]; ok {
book = b
} else {
book.limit = 4
cl.books[book.ISBN] = book
}
book.Register()
return book.Registered()
}
// AddBookJSON registers a book copy in the library from its JSON representation.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBookJSON(data []byte) (int, error) {
var book Book
json.Unmarshal(data, &book)
return cl.AddBook(&book)
}
// AddBookXML registers a book copy in the library from its XML representation.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBookXML(data []byte) (int, error) {
var book Book
xml.Unmarshal(data, &book)
return cl.AddBook(&book)
}
// GetBook returns a book from the library by its ISBN number and error if any occurs.
func (cl *ChannelLibrary) GetBook(isbn string) (*Book, error) {
cl.Lock()
defer cl.Unlock()
book, ok := cl.books[isbn]
if ok {
return book, nil
} else {
return nil, errors.New("Непозната книга " + isbn)
}
}
// Hello initiates communication with a librarian. Blocks if no librarian is free.
// Returns requests and responses channels that are used for the communication.
func (cl *ChannelLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
requests := make(chan LibraryRequest)
responses := make(chan LibraryResponse)
cl.librarians <- func() {
for request := range requests {
book, err := cl.GetBook(request.GetISBN())
var registered, available int
if err == nil {
switch request.GetType() {
case 1:
err = book.Borrow()
case 2:
err = book.Return()
case 3:
}
registered, _ = book.Registered()
available = book.Available()
}
responses <- &ChannelLibraryResponse{book, err, registered, available}
}
}
return requests, responses
}
// NewLibrary initializes a new ChannelLibrary with specific number of librarians.
func NewLibrary(librariansCount int) Library {
- librarians := make(chan func(), librariansCount)
+ librarians := make(chan func())
- go func() {
- for work := range librarians {
- work()
- }
- }()
+ for i := 0; i < librariansCount; i++ {
+ go func() {
+ for work := range librarians {
+ work()
+ }
+ }()
+ }
return &ChannelLibrary{
books: map[string]*Book{},
librarians: librarians,
}
}

Хей :) Като за начало премахни декларирането на интерфейсите от решението си. В условието сме споменали, че те ще бъдат декларирани при нас. Тяхното описание е дадено с цел да знаете с какво ще ви се налага да работите ( какво ще ви се налага да имплементирате ).

После погледни дали правилно броиш книгите.

Поздрави

Станислав обнови решението на 01.12.2015 22:22 (преди над 2 години)

package main
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"sync"
)
type Library interface {
// Добавя книга от json
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Aко са повече от 4 - връща грешка
AddBookJSON(data []byte) (int, error)
// Добавя книга от xml
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Ако са повече от 4 - връщаме грешка
AddBookXML(data []byte) (int, error)
// Ангажира свободен "библиотекар" да ни обработва заявките.
// Библиотекарите са фиксиран брой - подават се като параметър на NewLibrary
// Блокира ако всички библиотекари са заети.
// Връщат се два канала:
// първият е само за писане - по него ще изпращаме заявките
// вторият е само за четене - по него ще получаваме отговорите.
// Ако затворим канала със заявките - освобождаваме библиотекаря.
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type LibraryRequest interface {
// Тип на заявката:
// 1 - Borrow book
// 2 - Return book
// 3 - Get availability information about book
GetType() int
// Връща isbn на книгата, за която се отнася Request-a
GetISBN() string
}
type LibraryResponse interface {
// Ако книгата съществува/налична е - обект имплементиращ Stringer (повече информация по-долу)
// Aко книгата не съществува първият резултат е nil.
// Връща се и подобаващa грешка (виж по-долу) - ако такава е възникнала.
// Когато се е резултат на заявка от тип 2 (Return book) - не е нужно да я закачаме към отговора.
GetBook() (fmt.Stringer, error)
// available - Колко наличности от книгата имаме останали след изпълнението на заявката.
// Тоест, ако сме имали 3 копия от Х и това е отговор на Take заявка - тук ще има 2.
// registered - Колко копия от тази книга има регистрирани в библиотеката (макс 4).
GetAvailability() (available int, registered int)
}
// Author is a representation of a book author.
type Author struct {
FirstName string `json:"first_name" xml:"first_name"`
LastName string `json:"last_name" xml:"last_name"`
}
// String returns a string representation of the author.
func (a *Author) String() string {
return a.FirstName + " " + a.LastName
}
// Book is a representation of a book.
type Book struct {
- ISBN string `json:"isbn" xml:"isbn"`
+ ISBN string `json:"isbn" xml:"isbn,attr"`
Title string `json:"title" xml:"title"`
Author *Author `json:"author" xml:"author"`
Ratings []int `json:"ratings" xml:"ratings"`
sync.Mutex
limit int
registered int
borrowed int
}
// Register increments the number of copies of this book in the library.
-func (b *Book) Register() {
+func (b *Book) Register() error {
b.Lock()
defer b.Unlock()
if b.registered < b.limit {
b.registered++
+ return nil
+ } else {
+ return errors.New("Има 4 копия на книга " + b.ISBN)
}
}
// Borrow decrements the number of available copies of this book in the library.
func (b *Book) Borrow() error {
b.Lock()
defer b.Unlock()
var err error
if b.borrowed < b.registered {
b.borrowed++
} else {
err = errors.New("Няма наличност на книга " + b.ISBN)
}
return err
}
// Return increments the number of available copies of this book in the library.
func (b *Book) Return() error {
b.Lock()
defer b.Unlock()
var err error
if b.borrowed > 0 {
b.borrowed--
} else {
err = errors.New("Всички копия са налични " + b.ISBN)
}
return err
}
-// Registered returns the number of registered copies of this book in the library.
-func (b *Book) Registered() (int, error) {
- b.Lock()
- defer b.Unlock()
-
- total := b.registered
- if total < b.limit {
- return total, nil
- } else {
- return total, errors.New("Има 4 копия на книга " + b.ISBN)
- }
-}
-
// Available returns the number of available copies of this book in the library.
func (b *Book) Available() int {
b.Lock()
defer b.Unlock()
return b.registered - b.borrowed
}
// String returns a string representation of the book.
func (b *Book) String() string {
return "[" + b.ISBN + "] " + b.Title + " от " + b.Author.String()
}
// ChannelLibraryResponse is a representation of a response to a library request.
type ChannelLibraryResponse struct {
book *Book
err error
registered int
available int
}
// GetBook returns the target book of the library request and error if any occurs.
func (mr *ChannelLibraryResponse) GetBook() (fmt.Stringer, error) {
return mr.book, mr.err
}
// GetAvailability returns the available and registered copies of the target book.
func (mr *ChannelLibraryResponse) GetAvailability() (available int, registered int) {
return mr.available, mr.registered
}
// ChannelLibrary implements a library with librarians operating over a buffered channel.
type ChannelLibrary struct {
sync.Mutex
books map[string]*Book
librarians chan<- func()
}
// AddBook registers a book copy in the library.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBook(book *Book) (int, error) {
cl.Lock()
defer cl.Unlock()
if b, ok := cl.books[book.ISBN]; ok {
book = b
} else {
book.limit = 4
cl.books[book.ISBN] = book
}
- book.Register()
- return book.Registered()
+ err := book.Register()
+ return book.registered, err
}
// AddBookJSON registers a book copy in the library from its JSON representation.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBookJSON(data []byte) (int, error) {
var book Book
json.Unmarshal(data, &book)
return cl.AddBook(&book)
}
// AddBookXML registers a book copy in the library from its XML representation.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBookXML(data []byte) (int, error) {
var book Book
xml.Unmarshal(data, &book)
return cl.AddBook(&book)
}
// GetBook returns a book from the library by its ISBN number and error if any occurs.
func (cl *ChannelLibrary) GetBook(isbn string) (*Book, error) {
cl.Lock()
defer cl.Unlock()
book, ok := cl.books[isbn]
if ok {
return book, nil
} else {
return nil, errors.New("Непозната книга " + isbn)
}
}
// Hello initiates communication with a librarian. Blocks if no librarian is free.
// Returns requests and responses channels that are used for the communication.
func (cl *ChannelLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
requests := make(chan LibraryRequest)
responses := make(chan LibraryResponse)
cl.librarians <- func() {
for request := range requests {
book, err := cl.GetBook(request.GetISBN())
var registered, available int
if err == nil {
switch request.GetType() {
case 1:
err = book.Borrow()
case 2:
err = book.Return()
case 3:
}
- registered, _ = book.Registered()
+ registered = book.registered
available = book.Available()
}
responses <- &ChannelLibraryResponse{book, err, registered, available}
}
}
return requests, responses
}
// NewLibrary initializes a new ChannelLibrary with specific number of librarians.
func NewLibrary(librariansCount int) Library {
librarians := make(chan func())
for i := 0; i < librariansCount; i++ {
go func() {
- for work := range librarians {
- work()
+ for handleRequest := range librarians {
+ handleRequest()
}
}()
}
return &ChannelLibrary{
books: map[string]*Book{},
librarians: librarians,
}
}

Прав си за компилирането.

Промених условието и вече ще очакваме интерфейсите да са при вас.

Благодаря ти, че си си направил домашното по-рано и благодарение на това успяхме да хванем проблема!

Станислав обнови решението на 04.12.2015 13:06 (преди над 2 години)

package main
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"sync"
)
type Library interface {
// Добавя книга от json
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Aко са повече от 4 - връща грешка
AddBookJSON(data []byte) (int, error)
// Добавя книга от xml
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Ако са повече от 4 - връщаме грешка
AddBookXML(data []byte) (int, error)
// Ангажира свободен "библиотекар" да ни обработва заявките.
// Библиотекарите са фиксиран брой - подават се като параметър на NewLibrary
// Блокира ако всички библиотекари са заети.
// Връщат се два канала:
// първият е само за писане - по него ще изпращаме заявките
// вторият е само за четене - по него ще получаваме отговорите.
// Ако затворим канала със заявките - освобождаваме библиотекаря.
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type LibraryRequest interface {
// Тип на заявката:
// 1 - Borrow book
// 2 - Return book
// 3 - Get availability information about book
GetType() int
// Връща isbn на книгата, за която се отнася Request-a
GetISBN() string
}
type LibraryResponse interface {
// Ако книгата съществува/налична е - обект имплементиращ Stringer (повече информация по-долу)
// Aко книгата не съществува първият резултат е nil.
// Връща се и подобаващa грешка (виж по-долу) - ако такава е възникнала.
// Когато се е резултат на заявка от тип 2 (Return book) - не е нужно да я закачаме към отговора.
GetBook() (fmt.Stringer, error)
// available - Колко наличности от книгата имаме останали след изпълнението на заявката.
// Тоест, ако сме имали 3 копия от Х и това е отговор на Take заявка - тук ще има 2.
// registered - Колко копия от тази книга има регистрирани в библиотеката (макс 4).
GetAvailability() (available int, registered int)
}
// Author is a representation of a book author.
type Author struct {
FirstName string `json:"first_name" xml:"first_name"`
LastName string `json:"last_name" xml:"last_name"`
}
// String returns a string representation of the author.
func (a *Author) String() string {
return a.FirstName + " " + a.LastName
}
// Book is a representation of a book.
type Book struct {
ISBN string `json:"isbn" xml:"isbn,attr"`
Title string `json:"title" xml:"title"`
Author *Author `json:"author" xml:"author"`
Ratings []int `json:"ratings" xml:"ratings"`
sync.Mutex
limit int
registered int
borrowed int
}
// Register increments the number of copies of this book in the library.
func (b *Book) Register() error {
b.Lock()
defer b.Unlock()
if b.registered < b.limit {
b.registered++
return nil
} else {
return errors.New("Има 4 копия на книга " + b.ISBN)
}
}
// Borrow decrements the number of available copies of this book in the library.
func (b *Book) Borrow() error {
b.Lock()
defer b.Unlock()
var err error
if b.borrowed < b.registered {
b.borrowed++
} else {
err = errors.New("Няма наличност на книга " + b.ISBN)
}
return err
}
// Return increments the number of available copies of this book in the library.
func (b *Book) Return() error {
b.Lock()
defer b.Unlock()
var err error
if b.borrowed > 0 {
b.borrowed--
} else {
err = errors.New("Всички копия са налични " + b.ISBN)
}
return err
}
// Available returns the number of available copies of this book in the library.
func (b *Book) Available() int {
b.Lock()
defer b.Unlock()
return b.registered - b.borrowed
}
// String returns a string representation of the book.
func (b *Book) String() string {
return "[" + b.ISBN + "] " + b.Title + " от " + b.Author.String()
}
// ChannelLibraryResponse is a representation of a response to a library request.
type ChannelLibraryResponse struct {
book *Book
err error
registered int
available int
}
// GetBook returns the target book of the library request and error if any occurs.
func (mr *ChannelLibraryResponse) GetBook() (fmt.Stringer, error) {
return mr.book, mr.err
}
// GetAvailability returns the available and registered copies of the target book.
func (mr *ChannelLibraryResponse) GetAvailability() (available int, registered int) {
return mr.available, mr.registered
}
// ChannelLibrary implements a library with librarians operating over a buffered channel.
type ChannelLibrary struct {
sync.Mutex
books map[string]*Book
librarians chan<- func()
}
// AddBook registers a book copy in the library.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBook(book *Book) (int, error) {
cl.Lock()
defer cl.Unlock()
if b, ok := cl.books[book.ISBN]; ok {
book = b
} else {
book.limit = 4
cl.books[book.ISBN] = book
}
err := book.Register()
return book.registered, err
}
// AddBookJSON registers a book copy in the library from its JSON representation.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBookJSON(data []byte) (int, error) {
var book Book
json.Unmarshal(data, &book)
return cl.AddBook(&book)
}
// AddBookXML registers a book copy in the library from its XML representation.
// Returns the number of registered copies of the book and error if any occurs.
func (cl *ChannelLibrary) AddBookXML(data []byte) (int, error) {
var book Book
xml.Unmarshal(data, &book)
return cl.AddBook(&book)
}
// GetBook returns a book from the library by its ISBN number and error if any occurs.
func (cl *ChannelLibrary) GetBook(isbn string) (*Book, error) {
cl.Lock()
defer cl.Unlock()
book, ok := cl.books[isbn]
if ok {
return book, nil
} else {
return nil, errors.New("Непозната книга " + isbn)
}
}
// Hello initiates communication with a librarian. Blocks if no librarian is free.
// Returns requests and responses channels that are used for the communication.
func (cl *ChannelLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
requests := make(chan LibraryRequest)
responses := make(chan LibraryResponse)
cl.librarians <- func() {
for request := range requests {
book, err := cl.GetBook(request.GetISBN())
var registered, available int
if err == nil {
switch request.GetType() {
case 1:
err = book.Borrow()
case 2:
err = book.Return()
case 3:
}
registered = book.registered
available = book.Available()
}
responses <- &ChannelLibraryResponse{book, err, registered, available}
}
+ close(responses)
}
return requests, responses
}
// NewLibrary initializes a new ChannelLibrary with specific number of librarians.
func NewLibrary(librariansCount int) Library {
librarians := make(chan func())
for i := 0; i < librariansCount; i++ {
go func() {
for handleRequest := range librarians {
handleRequest()
}
}()
}
return &ChannelLibrary{
books: map[string]*Book{},
librarians: librarians,
}
}