go学习笔记(6)——音乐播放器实现

2023-05-16

声明:首先说明这个项目来自于许式伟的《Go语言编程》,书中也给出了详尽的源代码描述,不过代码中还是存在一些问题,首先说明一下所存在的问题

问题一:音乐的播放结构体中定义了五个属性字段,在后面赋值的时候又变成了六个字段的赋值

问题二:Play函数在调用的时候多传递了两个参数,在函数原型的时候只有两个参数

问题三:RemoveByName方法并没有实现

这两个问题应该都是为了后期更好的进行项目扩展,不过作为小白的我现在还是以学习和调通代码为主,再此基础上面在进行一步步的功能扩展,下面给出响应的项目说明和可以运行的实现基本功能的代码实现,所有的实现细节已经给出了详细的注释:

一:整体的逻辑框架


二:音乐库管理模块

》Len    求歌曲名长度

》Get    通过索引查找歌曲

》Find    通过名字查找歌曲

》Add    添加歌曲

》Remove    通过索引删除歌曲

》RemoveByName    通过歌名删除歌曲

package library

import (
	"errors"
	"fmt"
)

//定义音乐结构体
type MusicEntry struct {
	Id 	string		//音乐的唯一Id
	Name 	string		//音乐名
	Artist	string		//艺术家名
	Source	string		//音乐位置
	Type 	string		//音乐类型(MP3和WAV)
}

type MusicManager struct {
	musics	[]MusicEntry
}

func NewMusicManager() *MusicManager {
	return &MusicManager{make([]MusicEntry, 0)}
}

//获取歌曲的歌名长度
func (m *MusicManager) Len() int {
	return len(m.musics)
}

//通过下标获取歌曲
func (m *MusicManager) Get(index int) (music *MusicEntry, err error) {
	//未找到时报错,找到了下标对应的歌曲
	if index < 0 || index >= len(m.musics) {
		return nil, errors.New("Index out of range.")
	}
	return &m.musics[index], err
}

//通过对比名字查看要找的歌曲是否存在
func (m *MusicManager) Find(name string) *MusicEntry {
	if len(m.musics) == 0 {
		return nil
	}
	for _, m := range m.musics{
		if m.Name == name {
			return &m
		}
	}
	return nil
}

//添加歌曲
func (m *MusicManager) Add(music *MusicEntry)  {
	m.musics = append(m.musics, *music)
}

//通过下标删除歌曲
func (m *MusicManager) Remove(index int) *MusicEntry {
	if index < 0 || index > len(m.musics){
		return nil
	}
	removedMusic := m.musics[index]
	//从数组切片中删除元素
	if index < len(m.musics) - 1 {	//中间元素
		m.musics = append(m.musics[:index - 1], m.musics[index + 1:]...)
	}
	return &removedMusic
}

//通过歌名删除歌曲
func (m *MusicManager) RemoveByName(name string) *MusicEntry {
	removedMusic := m.Find(name)
	if removedMusic == nil{
		fmt.Println("Want to delete the song does not exist")
		return nil
	}
	return removedMusic
}

二:音乐管理单元测试模块(go单元测试测试将在后面的学习过程在详细说明,现在只要知道测试的重要性即可)

package library

import "testing"

func TestOps(t *testing.T) {
	mm := NewMusicManager()    //新建管理测试
	if mm == nil {
		t.Error("NewManagerMusic faild")
	}

	if mm.Len() != 0 {    //len测试
		t.Error("NewManagerMusic faild, not empty")
	}

	m0 := &MusicEntry{
		"1",
		"My Heart Will Go On",
		"Celion Dion",
		//"Pop",
		"http://qbox.me/24501234",
		"Mp3",
	}
	mm.Add(m0)    //添加测试
	if mm.Len() != 1 {
		t.Error("MusicManager.Add() failed")
	}

	m := mm.Find(m0.Name)    //find测试
	if m == nil {
		t.Error("MusicManager.Find() failed")
	}

	 if m.Id != m0.Id || m.Name != m0.Name || m.Artist != m0.Artist ||
		 m.Source != m0.Source || m.Type != m0.Type {
			t.Error("MusicManager.Find() failed. Find item mismatch")
	}

	m, err := mm.Get(0)    //get测试
	if m == nil {
		t.Error("MusicManager.Get() failed", err)
	}

	//空的时候直接进行测试会出问题
	m = mm.Remove(0)       //Remove测试
	if m == nil || mm.Len() != 0 {
		t.Error("MusicManager.Remove() failed", err)
	}
}

三:播放实现(播放包括的格式有MP3和WAV两种格式,当然再次也可以扩张使其支持其他格式的播放)

package mp

//音乐播放模块
import "fmt"

//设计一个简单的接口避免将MusicEntry中多余的信息传入
type Player interface {
	Play(Source string)
}

//播放实现,再此也可以在添加其他格式
func Play(Source, mtype string)  {
	var p Player

	switch mtype {
	case "MP3":		//MP3格式播放
		p = &MP3Player{}
	case "WAV":		//WAV格式播放
		p = &WAVPlayer{}
	default:
		fmt.Println("Unsupported music type", mtype)
		return
	}
	p.Play(Source)
}
package mp

import (
	"fmt"
	"time"
)

type MP3Player struct {
	stat 		int
	progress 	int
}

//MP3格式播放具体实现
func (p *MP3Player) Play(Source string) {
	fmt.Println("Playing MP3 music", Source)

	p.progress = 0

	for p.progress < 100 {
		time.Sleep(100 * time.Millisecond)		//假装正在播放
		fmt.Print(".")
		p.progress += 10
	}
	fmt.Println("\nFinished playing", Source)
}
package mp

import (
	"fmt"
	"time"
)

type MP3Player struct {
	stat 		int
	progress 	int
}

//MP3格式播放具体实现
func (p *MP3Player) Play(Source string) {
	fmt.Println("Playing MP3 music", Source)

	p.progress = 0

	for p.progress < 100 {
		time.Sleep(100 * time.Millisecond)		//假装正在播放
		fmt.Print(".")
		p.progress += 10
	}
	fmt.Println("\nFinished playing", Source)
}

四:主程序调用实现

package main

import (
	"goCode/src/music/library"
	"fmt"
	"strconv"
	"goCode/src/music/mp"
	"bufio"
	"os"
	"strings"
)

var lib *library.MusicManager
var id int = 1


//管理模块句柄实现
func handleLibCommands(tokens []string)  {
	switch tokens[1] {
	case "list":
		for i := 0; i < lib.Len(); i++ {
			e, _ := lib.Get(i)
			fmt.Println(i + 1, ":", e.Name, e.Artist, e.Source, e.Type)
		}
	case "add":
		if len(tokens) == 6 {
			id++
			lib.Add(&library.MusicEntry{strconv.Itoa(id),
			tokens[2], tokens[3], tokens[4], tokens[5]})
		}else {
			fmt.Println("USAGE: lib add <name><artist><source><type>")
		}
	case "remove":
		if len(tokens) == 3 {
			lib.RemoveByName(tokens[2])
		}else {
			fmt.Println("USAGE: lib remove <name>")
		}
	default:
		fmt.Println("Unrecognied lib commond:", tokens[1])
	}
}

//播放模块句柄实现
func handlePlayCommand(tokens []string)  {
	if len(tokens) != 2 {
		fmt.Println("USAGE: play <name>")
		return
	}

	e := lib.Find(tokens[1])
	if e == nil {
		fmt.Println("The Music", tokens[1], "does not exist")
		return
	}

	mp.Play(e.Source, e.Type)
}

func main()  {
	//打印操作菜单
	fmt.Println(`
		Enter following commands to control the player:
		lib list -- View the existing music lib
		lib add <name><artist><source><type> -- Add a music to the music lib
		lib remove <name> -- Remove the specified music from the lib
		play <name> -- Play the specified music
	`)
	lib = library.NewMusicManager()

	r := bufio.NewReader(os.Stdin)

	for{
		fmt.Print("Enter Command-> ")

		rawLine, _, _ := r.ReadLine()
		line := string(rawLine)

		//输入q或者e时退出播放器
		if line == "q" || line == "e" {
			break
		}

		tokens := strings.Split(line, " ")
		if tokens[0] == "lib" {
			handleLibCommands(tokens)
		}else if tokens[0] == "play"{
			handlePlayCommand(tokens)
		}else {
			fmt.Println("Unrecognized command:", tokens[0])
		}
	}
}

五:演示


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go学习笔记(6)——音乐播放器实现 的相关文章

  • 浅析TCP协议中的各种定时器

    TCP在建立连接之后可能会启动四个定时器 重传计时器 xff1a Retransmission Timer 坚持计时器 xff1a Persistent Timer 保活计时器 xff1a Keeplive Timer 时间等待计时器 xf
  • 【程序员面试宝典】字符串相关面试题

    1 确定字符互异 请实现一个算法 xff0c 确定一个字符串的所有字符是否全都不同给定一个string iniString xff0c 请返回一个bool值 True代表所有字符全都不同 xff0c False代表存在相同的字符 保证字符串
  • 【程序员面试宝典】链表相关面试题

    1 链表中的第k个节点 题目描述 xff1a 输入一个链表 xff0c 输出该链表中倒数第k个结点 struct ListNode span class hljs built in int span val struct ListNode
  • 【网络】网络端口号分类

    在开始之前有必要先说一下为什么要网络要对对端口号进行细分 xff0c 而像常见的端口号之间又是什么东西 xff0c 有什么作用 xff0c 为什么要学习端口号相关的知识 xff0c 带着这些疑问 xff0c 下面开始今天知识的学习 在我学习
  • TCP协议中的URG和PSH位

    相关背景知识 http blog csdn net double happiness article details 74025156 在探讨TCP协议中的URG和PSH控制位时 xff0c 我们先来简单的复习一下TCP协议 URG xff
  • 问答QA(一)综述

    声明 xff1a 本文是综合网上问答系统介绍 xff0c 做的总结 xff0c 如有侵权 xff0c 请联系处理 xff0c 谢谢 一 问答系统架构 1 1 问题分析模块 负责对用户的提问进行处理 xff1b 生成查询关键词 xff08 提
  • 【程序员面试宝典】栈和队列相关面试题

    1 集合栈 题目描述 xff1a 请实现一种数据结构SetOfStacks xff0c 由多个栈组成 xff0c 其中每个栈的大小为size xff0c 当前一个栈填满时 xff0c 新建一个栈 该数据结构应支持与普通栈相同的push和po
  • 【程序员面试宝典】栈的应用

    1 下一个较大元素 现在我们有一个int数组 xff0c 请你找出数组中每个元素的下一个比它大的元素 给定一个int数组A及数组的大小n xff0c 请返回一个int数组 xff0c 代表每个元素比他大的下一个元素 若不存在则为 1 保证数
  • time_wait与面试的暧昧

    背景知识 TCP三次握手与四次挥手 http blog csdn net double happiness article details 70160738 time wait是什么 xff1f 通过上面三次握手和四次挥手的学习 xff0c
  • 【通信方式五】socket编程之TCP通信

    1 网络字节序 网络字节序就是熟知的关于大小端的问题 xff0c 关于前面的大小端的判断方法 xff0c 以及代码实现再此就不在赘述 xff0c 下面只谈网络中的字节序问题 xff08 如何判定当前机器的大小端 xff1a http blo
  • 【通信方式六】socket编程之UDP通信

    相关博客 通信方式五 socket编程之TCP http blog csdn net double happiness article details 74938008 由于TCP协议是可靠的面向连接的协议 xff0c 因此在服务器端需要执
  • shell下的第一个编程(不一样的1到100累加)

    相信对于一个程序 猿 来说 xff0c 除了我们入门的 hello world 之外 xff0c 最简单的代码就是只有从1累加到100这样简单的程序吧 xff0c 没错这样的程序在现在来看或许根本不如我们的法眼 xff0c 那么问题来了 x
  • 【每日一题-1】有序链表合并与累加和问题

    基础题 合并两个有序链表 xff0c 合并以后的链表依旧有序 思路 xff1a xff08 1 xff09 特殊情况处理 xff1a 若两个链表都为则返回空 xff0c 若其中一个链表为空返回另外一个链表的头结点 xff1b xff08 2
  • 【每日一题-2】链表基础面试题

    1 查找链表的倒数第k个节点 span style font family none font size 12px ListNode FindKthToTail ListNode pListHead unsigned int k if pL
  • 【每日一题-3】链表带环问题

    判断链表是否带环 xff1f 如果带环 xff0c 环的长度是多少 xff1f 环的入口节点是什么 xff1f span style font family none font size 12px struct ListNode int v
  • Linux更改镜像源

    https mirrors tuna tsinghua edu cn span class token comment 清华大学镜像源 span span class token comment 1 搜索Ubuntu span span c
  • 【每日一题-5】复杂链表的复制

    逆序打印单链表 span style font family none font size 12px void ReversePrintList listNode pHead if pHead 61 61 NULL return NULL
  • 【每日一题-6】栈和队列与替换空格

    两个栈实现一队列 span style font family none font size 12px class Queue void Push int data inStack push data int Pop if inStack
  • HTTP协议详解(真的很牛逼)

    引言 HTTP是一个属于应用层的面向对象的协议 xff0c 由于其简捷 快速的方式 xff0c 适用于分布式超媒体信息系统 它于1990年提出 xff0c 经过几年的使用与发展 xff0c 得到不断地完善和扩展 目前在WWW中使用的是HTT
  • shell下的命令代替

    命令替换是指Shell 执行命令并将命令替换部分替换为执行该命令后的结果 shell下的命令代替为 34 96 96 xff08 反引号 xff09 34 和 34 34 使用单反引号的替换方式 执行结果 替换成 的方式 执行结果 两种命令

随机推荐