在这篇文章中,我们将带领您了解Golang(6)WebBasic的全貌,同时,我们还将为您介绍有关asp-classic–升级ClassicASPWebApp的最佳方法是什么?建议和意见需要、Gola
在这篇文章中,我们将带领您了解Golang(6)Web Basic的全貌,同时,我们还将为您介绍有关asp-classic – 升级Classic ASP WebApp的最佳方法是什么?建议和意见需要、Golang - Mysql ang Http Basic fucntions、GoLang basic、Golang Basic - select and channel usage的知识,以帮助您更好地理解这个主题。
本文目录一览:- Golang(6)Web Basic
- asp-classic – 升级Classic ASP WebApp的最佳方法是什么?建议和意见需要
- Golang - Mysql ang Http Basic fucntions
- GoLang basic
- Golang Basic - select and channel usage
Golang(6)Web Basic
Golang(6)Web Basic
3.1 How Go Work with Web
URL (Uniform Request Locator)
DNS (Domain Name System)
TCP ——> HTTP (80 port TCP)
Http Request
Http Request —> Request Line,Request Header,Request Body
GET /domains/example/ HTTP/1.1 //Request Line: Request Method
Host: www.iana.org //server host name
User-Agent
Accept //Client mine
Accept-Encoding //
Accept-Charset //Client Charset
Body
Http Response
HTTP/1.1 200 OK //response status Line
Server: Nginx/1.0.8 //Web Server software name and version
Date: Tue,30 Oct 2012 04:14:25 GMT //sending time
Content-Type: text/html //Server side data mine
transfer-encoding: chunked //
Connection: keep-alive
Content-Length: 90 //length of the body
<!Document html>…. Body
4XX client errors,5XX server side errors,2XX success,3XX redirect,1XX info
Keep-Alive
After HTTP/1.1,Keep-Alive will default be true. We can reuse the TCP connection. This Keep-Alive time can be set on the server side configuration.
3.2 Construct the Web Server based on Go
The Simplest Server based on http package
package main
import (
"fmt"
"log"
"net/http"
"strings"
)
func sayhelloName(w http.ResponseWriter,r *http.Request) {
r.ParseForm() //解析参数,默认是不会解析的
fmt.Println("form: ",r.Form) //这些信息是输出到服务器端的打印信息
fmt.Println("path: ",r.URL.Path)
fmt.Println("scheme: ",r.URL.Scheme)
fmt.Println(r.Form["url_long"])
for k,v := range r.Form {
fmt.Println("key:",k)
fmt.Println("val:",strings.Join(v,""))
}
fmt.Fprintf(w,"Hello astaxie!") //这个写入到w的是输出到客户端的
}
func main() {
http.HandleFunc("/",sayhelloName) //设置访问的路由
err := http.ListenAndServe(":9090",nil) //设置监听的端口
if err != nil {
log.Fatal("ListenAndServe: ",err)
}
}
Visit the http://localhost:9090 to see the result.
3.3 Further Work to Build Web
Some Concepts from Server Side
Request,Response,Connection,Handler
How http Package Works
for {
rw,e := l.Accept()
if e != nil {
}
c,err := srv.newConn(rw)
if err != nil {
continue
}
go c.serve()
}
handler is the second parameter of ListenAndServe,if it is nil,we will use handler = DefaultServeMux
3.4 Details of http Package
There are 2 key functions in http: Conn,ServeMux
Conn and Concurrence
c,err := srv.newConn(rw)
if err != nil {
continue
}
go c.serve()
Customer ServeMux
How the old codes work
type ServeMux struct {
mu sync.RWMutex //lock
m map[string]muxEntry
hosts bool // if put the host in the mapping rules
}
type muxEntry struct {
explicit bool //match exactly
h Handler
pattern string
}
type Handler interface {
ServeHTTP(ResponseWriter,*Request)
}
When we call method HandlerFuc,it will convert the function to contains method ServHTTP
type HandlerFunc func(ResponseWriter,*Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter,r *Request) {
f(w,r)
}
Map the Rules and then Call the Handler
Customer Mapping
package main
import (
"fmt"
"net/http"
)
type MyMux struct {
}
func (p *MyMux) ServeHTTP(w http.ResponseWriter,r *http.Request) {
if r.URL.Path == "/" {
sayhelloName(w,r)
return
}
http.NotFound(w,r)
return
}
func sayhelloName(w http.ResponseWriter,r *http.Request) {
fmt.Fprintf(w,"Hello myroute!")
}
func main() {
mux := &MyMux{}
http.ListenAndServe(":9090",mux)
}
4. Forms
…snip...
References:
https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/03.0.md
asp-classic – 升级Classic ASP WebApp的最佳方法是什么?建议和意见需要
细节:
>在Windows Small Business Server 2008上运行
>经典ASP,JavaScript,CSS和Javascript的组合
>访问数据库后端
>大型系统,包含约135页,总共2.3 MB
目标:
>以小方式扩展功能
>可能会转向不同语言以便于维护(AJAX?)
>从HTML结构中分离代码(目前非常混乱)
1)鉴于我没有足够的时间来完全重写系统,继续使用ASP和JavaScript是明智的吗?
2)我已经看过一些AJAX,看起来将它包含在页面中是一个轻松的飞跃,这是一个值得追求的途径吗?
3)是否值得研究MVC框架?如果是这样,是否需要使用某种类型的库正式完成,或者我是否可以遵循使用ASP实现MVC功能的最佳实践?
4)升级到“真正的”DBMS(例如MysqL)和移植数据库有多困难?值得做吗? (随意打电话访问)
对不起,我只是迷失了大量的Web标准,语言和实践.
解决方法
3)根据我的经验,移植这么大的系统并不是一个好主意.
ASP Classic在IIS 7.5和IIS Express下运行顺畅,因此您可以使用Url Rewrite和其他IIS插件等优点.如果在ASP经典页面中需要更多功能,只需将它们与ASP.NET页面结合使用即可.将它们并排运行没有问题,如果我需要.NET Framework的强大功能来完成动态生成的Zip文件等任务,我通常会使用ASP.NET通用处理程序(.ashx).
4)升级到sql Server Express.
Microsoft SQL Server Migration Assistant (SSMA)将帮助您将Access DB转换为sql Server.我之前使用1 GB(无二进制数据)200表数据库并在一周内将旧的ASP系统迁移到sql Server.
使用Jquery,IIS 7.5或IIS Express,.Net Framework 4.0和sql Server 2008 Express,您可以在比完全移植系统更短的时间内“移植”您的系统.
Golang - Mysql ang Http Basic fucntions
今天总结了一些Golang的基本用法,作为记录在此!
package main import ( "database/sql" "fmt" "io/IoUtil" "log" _ "MysqL-master/MysqL-master" "net/http" "strings" ) func httpGet(url string) { resp,err := http.Get(url) if err != nil { // handle error } defer resp.Body.Close() body,err := IoUtil.ReadAll(resp.Body) if err != nil { // handle error } fmt.Println(string(body)) } func httpPost(url string) { resp,err := http.Post(url,"application/x-www-form-urlencoded",strings.NewReader("name=cjb")) if err != nil { fmt.Println(err) } defer resp.Body.Close() body,err := IoUtil.ReadAll(resp.Body) if err != nil { // handle error } fmt.Println(string(body)) } func getConn() *sql.DB { //db,err := sql.Open("MysqL","root:1234@tcp(localhost:3306)/psmdb") db,"root:1234@tcp(localhost:3306)/psmdb") if err != nil { //log.Println(err) } err = db.Ping() if err != nil { log.Fatal(err) } println("connection MysqL success.") return db } func query(db *sql.DB) { rows,err := db.Query("select id,username from psm_user where username = ?","changeit") if err != nil { log.Println(err) } defer rows.Close() var id int var name string for rows.Next() { err := rows.Scan(&id,&name) if err != nil { log.Fatal(err) } fmt.Println("id:",id,",name:",name) } err = rows.Err() if err != nil { log.Fatal(err) } fmt.Println("query success") } func insert(db *sql.DB) { stmt,err := db.Prepare("INSERT INTO psm_user(username,password) VALUES(?,?)") defer stmt.Close() if err != nil { log.Println(err) } stmt.Exec("changeit","1234") fmt.Println("insert success") } func delete(db *sql.DB) { tx,_ := db.Begin() stmt,err := db.Prepare("DELETE FROM psm_user WHERE username=?") stmt.Exec("changeit") defer stmt.Close() if err != nil { // hand err tx.Rollback() fmt.Println("delete error") } tx.Commit() fmt.Println("delete success") } func update(db *sql.DB) { tx,err := db.Prepare("update psm_user set username = ?,password = ?") stmt.Exec("changeit") stmt.Exec("1234") defer stmt.Close() if err != nil { // hand err tx.Rollback() fmt.Println("update error") } tx.Commit() fmt.Println("update success") } func main() { httpGet("http://localhost:8088/SpringDemo/home/users/1") httpPost("http://localhost:8088/SpringDemo/home/user") db := getConn() insert(db) query(db) update(db) delete(db) }结果输出:
[ `go run main.go` | done: 5.25s ] {"id":1,"username":"admin","password":"1234"} {"id":2,"username":"hpe4test","password":"1234"} insert success id: 7,name: changeit query success update success delete success connection MysqL success. [ C:/MyGo/src/ ] #
注:
驱动下载地址:https://github.com/go-sql-driver/MysqL/GoLang basic
1 Go 的基础组成有以下几部分
- 包声明
- 引入包
- 函数
- 变量
- 语句&表达式
- 注释
package main
import "fmt"
func main(){
/**/
fmt.Println("hello,world!")
}
- 每个 Go 应用程序都包含一个名为 main 的包
- fmt 包实现了格式化 IO(输入/输出)的函数
- 下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )
需要注意的是 { 不能单独放在一行,所以以下代码在运行时会产生错误:
···
文件名与包名没有直接关系,不一定要将文件名与包名定成同一个。
文件夹名与包名没有直接关系,并非需要一致。
同一个文件夹下的文件只能有一个包名,否则编译报错。
···
Go 语法基础
Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号。如以下 GO 语句由 6 个标记组成:
数据类型
Go语言变量
声明变量的一般形式是使用 var 关键字:
var identifier type
package main
import "fmt"
function main(){
var a string = "Runoob"
fmt.Println(a)
var b,c int = 1,2
fmt.Println(b,c)
变量声明
- 第一种,指定变量类型,如果没有初始化,则变量默认为零值
- 第二种,根据值自行判断变狼类型
- 第三种,省略var,注意:=左侧如果没有声明新的变量,就产生编译错误
intVal := 1 // 此时不会产生编译错误,因为有声明新的变量,因为 := 是一个声明语句
相当于
var intVal int
intVal =1
多变量声明
//类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3
var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断
vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
// 这种因式分解关键字的写法一般用于声明全局变量
var (
vname1 v_type1
vname2 v_type2
)
值类型和引用类型
Go语言常量
const identifier [type] = value
多个相同类型的声明可以简写为:
const c_name1, c_name2 = value1, value2
常量还可以用作枚举
const (
Unknown = 0
Female = 1
Male = 2
)
iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
iota 可以被用作枚举值:
const (
a = iota
b = iota
c = iota
)
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
package main
import "fmt"
const (
i=1<<iota
j=3<<iota
k
l
)
func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}
以上实例运行结果为
i= 1
j= 6
k= 12
l= 24
Go 语言运算符
其他运算符
Go 语言条件语句
switch
switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。
switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough 。
switch var1 {
case val1:
...
case val2:
...
default:
...
}
Go语言循环
for 循环
for init; condition; post{}
for condition{}
for{}
for 循环的range格式可以对slice、map、数组、字符串等进行迭代循环
for key,value := range oldMap{
newMap[key] = vaule
}
package main
import "fmt"
func main() {
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
numbers := [6]int{1, 2, 3, 5}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
}
Go 语言函数
func function_name( [parameter list] ) [return_types] {
函数体
}
返回多个值
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
}
函数参数
默认情况下, Go语言使用的事值传递,即再调用过程中不会影响到实际参数
函数用法
函数作为另外一个函数的实参
package main import ( "fmt" "math ) func main(){ getSquareRoot := func(x float64) float64{ return math.Sqrt(x) } fmt.Println(getSquareRoot(9)) }
- 闭包
Go 语言支持匿名函数,可作为闭包。 匿名函数是一个”内联“语句或表达式。匿名函数的优越性在于可以直接使用函数内部的变量,不必申明。
package main
import "fmt"
func getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}
func main(){
nextNumber := getSequence()
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
- 方法
Go语言变量作用域
作用域为以生命标识符所表示的常量、类型、变量、函数或包再源代码中的作用范围。
int -> 0
float32 -> 0
pointer -> nil
Go语言数组
声明数组
var variable_name [size] variable_type
var balance [10] float32
初始化数组
var balance = [5]float32{100.0,2.0.3.4,7.0,50.0}
balance := [5]float32{1000.0,2.0,3.4,6.0,50.0}
如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
或
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
如果设置了数组的长度,我们还可以通过指定下标来初始化元素:
// 将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0,3:7.0}
多维数组
var variable_name [size1][size2]...[sizeN] variable_type
var threadim [5][10][4]int
初始化二维数组
a := [3][4]int{
{0,1,2,3},
{4,5,6,7},
{8,9,10,11},
}
注意:以上代码中倒数第二行的 } 必须要有逗号,因为最后一行的 } 不能单独一行,也可以写成这样:
a := [3][4]int{
{0, 1, 2, 3} , /* 第一行索引为 0 */
{4, 5, 6, 7} , /* 第二行索引为 1 */
{8, 9, 10, 11}} /* 第三行索引为 2 */
向函数传递数组
方式一
设置形参大小
void myFunction(param [10]int)
{
...
}
方式二
未设置数组大小
void myFunction(param []int)
{
...
}
指针
如何使用指针:
- 定义为指针变量
- 为指针变量赋值
- 访问指针变量中指向地址的值
当一个指针被定义后没分配到任何变量时,它的值为nil
nil和其他语言的null,None,NULL一样,代指一切零值或空值
package main
import "fmt"
func main(){
var pte *int
fmt.Printf("prt is:%x\n",ptr)
}
指针数组
var ptr [MAX]*int;
package main
import "fmt"
const MAX int = 3
func main(){
a := []int{10,100,200}
var i int
var ptr [MAX]*int
for i=0;i<MAX;i++{
prt[i] = &a[i]
}
for i=0;i<MAX;i++{
fmt.Printf("a[%d] = %d\n",i,*ptr[i])
}
}
指向指针的指针
如果一个指针变量存放的又是另一个指针变量的地址,那么这个指针变量为指向指针的指针变量
var prt **int
package main
import "fmt"
func main(){
var a int
var ptr *int
var pptr **int
a = 3000
ptr = &a
pptr = &ptr
fmt.Printf("变量 a = %d\n",a)
fmt.Printf("变量 *ptr = %d=n",*ptr)
fmt.Printf("变量 **pptr = %d\n",**pptr)
}
Go语言指针作为函数参数
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int= 200
fmt.Printf("交换前 a 的值 : %d\n", a )
fmt.Printf("交换前 b 的值 : %d\n", b )
/* 调用函数用于交换值
* &a 指向 a 变量的地址
* &b 指向 b 变量的地址
*/
swap(&a, &b);
fmt.Printf("交换后 a 的值 : %d\n", a )
fmt.Printf("交换后 b 的值 : %d\n", b )
}
func swap(x *int, y *int) {
var temp int
temp = *x /* 保存 x 地址的值 */
*x = *y /* 将 y 赋值给 x */
*y = temp /* 将 temp 赋值给 y */
}
结构体
type struct_variable_type struct {
member definition
member definition
....
member definition
}
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
// 创建一个新的结构体
fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
// 也可以使用 key => value 格式
fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
// 忽略的字段为 0 或 空
fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
}
如果要访问结构体成员,需要使用点号 . 操作符
结构体作为函数参数
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407
/* book 2 描述 */
Book2.title = "Python 教程"
Book2.author = "www.runoob.com"
Book2.subject = "Python 语言教程"
Book2.book_id = 6495700
/* 打印 Book1 信息 */
printBook(Book1)
/* 打印 Book2 信息 */
printBook(Book2)
}
func printBook( book Books ) {
fmt.Printf( "Book title : %s\n", book.title)
fmt.Printf( "Book author : %s\n", book.author)
fmt.Printf( "Book subject : %s\n", book.subject)
fmt.Printf( "Book book_id : %d\n", book.book_id)
}
结构体指针
var struct_pointer *Books
struct_pointer = &Book1
struct_pointer.title
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407
/* book 2 描述 */
Book2.title = "Python 教程"
Book2.author = "www.runoob.com"
Book2.subject = "Python 语言教程"
Book2.book_id = 6495700
/* 打印 Book1 信息 */
printBook(&Book1)
/* 打印 Book2 信息 */
printBook(&Book2)
}
func printBook( book *Books ) {
fmt.Printf( "Book title : %s\n", book.title)
fmt.Printf( "Book author : %s\n", book.author)
fmt.Printf( "Book subject : %s\n", book.subject)
fmt.Printf( "Book book_id : %d\n", book.book_id)
}
Go 语言切片
Go 语言切片是对数组的抽象。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
定义切片
声明一个未指定大小的数组来定义切片:
var identifier []type
使用make()创建切片
var slice1 []type = make([]type, len)
slice1 := make([]type, len)
也可以指定容量
make([]T, length, capacity)
切片初始化
s :=[]int {1,2,3}
s := arr[:]
s := arr[startIndex:endIndex]
from startIndex -> endIndex-1
s :=make([]int, len, cap)
len()和cap()
切片是可索引的,并且可以有len()方法获取长度
切片提供了计算容量的方法
package main
import "fmt"
func main() {
var numbers = make([]int,3,5)
printSlice(numbers)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
切片截取
package main
import "fmt"
func main() {
/* 创建切片 */
numbers := []int{0,1,2,3,4,5,6,7,8}
printSlice(numbers)
/* 打印原始切片 */
fmt.Println("numbers ==", numbers)
/* 打印子切片从索引1(包含) 到索引4(不包含)*/
fmt.Println("numbers[1:4] ==", numbers[1:4])
/* 默认下限为 0*/
fmt.Println("numbers[:3] ==", numbers[:3])
/* 默认上限为 len(s)*/
fmt.Println("numbers[4:] ==", numbers[4:])
numbers1 := make([]int,0,5)
printSlice(numbers1)
/* 打印子切片从索引 0(包含) 到索引 2(不包含) */
number2 := numbers[:2]
printSlice(number2)
/* 打印子切片从索引 2(包含) 到索引 5(不包含) */
number3 := numbers[2:5]
printSlice(number3)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
append() 和 copy()
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
/* 允许追加空切片 */
numbers = append(numbers, 0)
printSlice(numbers)
/* 向切片添加一个元素 */
numbers = append(numbers, 1)
printSlice(numbers)
/* 同时添加多个元素 */
numbers = append(numbers, 2,3,4)
printSlice(numbers)
/* 创建切片 numbers1 是之前切片的两倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)
/* 拷贝 numbers 的内容到 numbers1 */
copy(numbers1,numbers)
printSlice(numbers1)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
接口
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* 定义结构体 */
type struct_name struct {
/* variables */
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* 方法实现*/
}
package main
import (
"fmt"
)
type Phone interface {
call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
}
func (iPhone IPhone) call() {
fmt.Println("I am iPhone, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
错误处理
Go语言通过内置的错误接口提供了非常简单的错误处理机制
error类型是一个接口类型:
type error inteface{
Error() string
}
我们可以再编码中通过时间error接口类型来生成错误信息
函数通常再最后的返回值中返回错误信息
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// 实现
}
result, err:= Sqrt(-1)
if err != nil {
fmt.Println(err)
}
Go并发
Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
go func_name(parameter_list)
Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
world
hello
hello
world
world
hello
hello
world
world
hello
通道channel
通道(channel)是用来传递数据的一个数据结构。
通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
ch <- v // 把 v 发送到通道 ch
v := <-ch // 从 ch 接收数据
// 并把值赋给 v
声明一个通道很简单,我们使用chan关键字即可,通道在使用前必须先创建:
ch := make(chan int)
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 把 sum 发送到通道 c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 从通道 c 中接收
fmt.Println(x, y, x+y)
}
通道缓冲区
通道可以设置缓冲区, 通过make的第二个参数指定缓冲区的大小
ch :=make(chan int, 100)
带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于一部状态,就是说发送端发送的是护具可以放在缓冲区里面,然后等待接收端去获取数据,而不是立刻需要接收端去获取数据。
不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。
如果通道不带缓冲,发送方回阻塞直到接收方从通道中接受了值。如果通道带缓冲,发送方回阻塞知道发送的值被拷贝到缓冲区中;如果缓冲区已满,则意味着需要等待知道某个接收方获取到一个值。接收方再有值可以接受之前,会一直阻塞。
package main
import "fmt"
func main() {
// 这里我们定义了一个可以存储整数类型的带缓冲通道
// 缓冲区大小为2
ch := make(chan int, 2)
// 因为 ch 是带缓冲的通道,我们可以同时发送两个数据
// 而不用立刻需要去同步读取数据
ch <- 1
ch <- 2
// 获取这两个数据
fmt.Println(<-ch)
fmt.Println(<-ch)
}
Go 遍历通道与关闭通道
Go通过range关键字来实现遍历读取到的数据,类似于数组切片。
v,ok := <-ch
package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
// range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
// 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
// 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
// 会结束,从而在接收第 11 个数据的时候就阻塞了。
for i := range c {
fmt.Println(i)
}
}
Golang Basic - select and channel usage
今天学习了一下Golang 的 tag,select 和 channel ,记录在此!
1.tag 的作用
package main import ( "encoding/json" "fmt" "reflect" ) type Accout struct { UserId int `json:"user_id" bson:"user_id"` UserName string `json:"user_name" bson:"user_name"` Password string `json:"pass_word" bson:"pass_word"` } func main() { account := &Accout{UserId: 1,UserName: "justin",Password: "12345"} accountJson,_ := json.Marshal(account) fmt.Println(string(accountJson)) t := reflect.TypeOf(account) for i := 0; i < 3; i++ { field := t.Elem().Field(i) fmt.Println(field.Tag.Get("json")) fmt.Println(field.Tag.Get("bson")) } }输出:
{"user_id":1,"user_name":"justin","pass_word":"12345"} user_id user_id user_name user_name pass_word pass_word2.select 和 channel
package main import ( "fmt" "strconv" "time" ) func test1() { ch1 := make(chan int,1) ch2 := make(chan int,1) ch1 <- 1 ch2 <- 1 select { case <-ch1: fmt.Println("ch1 pop one element") case <-ch2: fmt.Println("ch2 pop one element") } } func test2() { timeout := make(chan bool,1) ch := make(chan int,1) ch <- 1 go func() { time.Sleep(3000) timeout <- true }() select { case <-ch: fmt.Println("got value") case <-timeout: fmt.Println("timeout") } } func test3() { taskChan := make(chan string,3) doneChan := make(chan bool,1) for i := 0; i < 3; i++ { taskChan <- strconv.Itoa(i) fmt.Println("send: ",i) } go func() { for i := 0; i < 3; i++ { task := <-taskChan fmt.Println("received: ",task) } doneChan <- true }() <-doneChan } func main() { test2() }这里的go function是在新的线程里面执行,而返回的结果可以到主线程中。
今天关于Golang(6)Web Basic的分享就到这里,希望大家有所收获,若想了解更多关于asp-classic – 升级Classic ASP WebApp的最佳方法是什么?建议和意见需要、Golang - Mysql ang Http Basic fucntions、GoLang basic、Golang Basic - select and channel usage等相关知识,可以在本站进行查询。
本文标签: