
一行:
我为什么要使用它们:x.(T)断言这x不是nil并且存储的值x是typeT。
- 检查
x
为零 - 检查它是否可转换(断言)为另一种类型
- 转换(断言)为另一种类型
t := x.(T)
=> t是类型T
;如果x
为零,则表示恐慌。t,ok := x.(T)
=>如果x
是零或不类型T
=>ok
是false
否则ok
是true
与t
是类型的T
。
详细说明
假设您需要计算4种不同形状的面积:圆形,正方形,矩形和三角形。您可以使用称为的新方法来定义新类型
Area(),如下所示:
type Circle struct { Radius float64}func (t Circle) Area() float64 { return math.Pi * t.Radius * t.Radius}对于
Triangle:
type Triangle struct { A, B, C float64 // lengths of the sides of a triangle.}func (t Triangle) Area() float64 { p := (t.A + t.B + t.C) / 2.0 // perimeter half return math.Sqrt(p * (p - t.A) * (p - t.B) * (p - t.C))}对于
Rectangle:
type Rectangle struct { A, B float64}func (t Rectangle) Area() float64 { return t.A * t.B}对于
Square:
type Square struct { A float64}func (t Square) Area() float64 { return t.A * t.A}在这里,您有
Circle,其半径为1.0,其侧面具有其他形状:
shapes := []Shape{ Circle{1.0}, Square{1.772453}, Rectangle{5, 10}, Triangle{10, 4, 7},}有趣!我们如何将它们全部收集在一个地方?
首先,您需要
Shape interface将它们全部收集成一片形状
[]Shape:
type Shape interface { Area() float64}现在,您可以像这样收集它们:
shapes := []Shape{ Circle{1.0}, Square{1.772453}, Rectangle{5, 10}, Triangle{10, 4, 7},}毕竟,
Circle是
Shape和
Triangle是
Shape太。
现在,您可以使用单个语句打印每个形状的区域
v.Area():
for _, v := range shapes { fmt.Println(v, "tArea:", v.Area())}Area()所有形状之间的通用接口也是如此。现在,我们如何使用上述方法来计算和调用像三角形的角之类的不常见方法
shapes?
func (t Triangle) Angles() []float64 { return []float64{angle(t.B, t.C, t.A), angle(t.A, t.C, t.B), angle(t.A, t.B, t.C)}}func angle(a, b, c float64) float64 { return math.Acos((a*a+b*b-c*c)/(2*a*b)) * 180.0 / math.Pi}现在是时候
Triangle从上方提取
shapes:
for _, v := range shapes { fmt.Println(v, "tArea:", v.Area()) if t, ok := v.(Triangle); ok { fmt.Println("Angles:", t.Angles()) }}使用
t, ok := v.(Triangle)我们要求的类型断言,这意味着我们要求编译器尝试将
vtype 转换
Shape为type
Triangle,以便如果成功,
ok则将为
true否则
false,然后如果成功,则调用
t.Angles()计算三角形的三个角度。
这是输出:
Circle (Radius: 1) Area: 3.141592653589793Square (Sides: 1.772453) Area: 3.1415896372090004Rectangle (Sides: 5, 10) Area: 50Triangle (Sides: 10, 4, 7) Area: 10.928746497197197Angles: [128.68218745348943 18.194872338766785 33.12294020774379]
以及整个工作示例代码:
package mainimport "fmt"import "math"func main() { shapes := []Shape{ Circle{1.0}, Square{1.772453}, Rectangle{5, 10}, Triangle{10, 4, 7}, } for _, v := range shapes { fmt.Println(v, "tArea:", v.Area()) if t, ok := v.(Triangle); ok { fmt.Println("Angles:", t.Angles()) } }}type Shape interface { Area() float64}type Circle struct { Radius float64}type Triangle struct { A, B, C float64 // lengths of the sides of a triangle.}type Rectangle struct { A, B float64}type Square struct { A float64}func (t Circle) Area() float64 { return math.Pi * t.Radius * t.Radius}// Heron's Formula for the area of a trianglefunc (t Triangle) Area() float64 { p := (t.A + t.B + t.C) / 2.0 // perimeter half return math.Sqrt(p * (p - t.A) * (p - t.B) * (p - t.C))}func (t Rectangle) Area() float64 { return t.A * t.B}func (t Square) Area() float64 { return t.A * t.A}func (t Circle) String() string { return fmt.Sprint("Circle (Radius: ", t.Radius, ")")}func (t Triangle) String() string { return fmt.Sprint("Triangle (Sides: ", t.A, ", ", t.B, ", ", t.C, ")")}func (t Rectangle) String() string { return fmt.Sprint("Rectangle (Sides: ", t.A, ", ", t.B, ")")}func (t Square) String() string { return fmt.Sprint("Square (Sides: ", t.A, ")")}func (t Triangle) Angles() []float64 { return []float64{angle(t.B, t.C, t.A), angle(t.A, t.C, t.B), angle(t.A, t.B, t.C)}}func angle(a, b, c float64) float64 { return math.Acos((a*a+b*b-c*c)/(2*a*b)) * 180.0 / math.Pi}另请参阅:
类型断言
对于具有接口类型和类型T的表达式x,主要表达式
x.(T)断言x不为nil,并且x中存储的值的类型为T。符号x。(T)称为类型断言。
更准确地说,如果T不是接口类型,则x。(T)断言x的动态类型与T的类型相同。在这种情况下,T必须实现x的(接口)类型。否则,类型断言无效,因为x不可能存储类型T的值。如果T是接口类型,则x。(T)断言x的动态类型实现了接口T。
如果类型断言成立,则表达式的值为存储在x中的值,其类型为T。 如果类型断言为false,则会发生运行时恐慌。
换句话说,即使x的动态类型仅在运行时才知道,但在正确的程序中x。(T)的类型还是T。var x interface{} = 7 // x has dynamic type int and value 7i := x.(int)// i has type int and value 7type I interface { m() }var y Is := y.(string) // illegal: string does not implement I (missingmethod m)
r := y.(io.Reader) // r has type io.Reader and y must implement both
I and io.Reader在特殊形式的赋值或初始化中使用的类型断言
v, ok = x.(T)v, ok := x.(T)var v, ok = x.(T)产生另一个无类型的布尔值。如果断言成立,则ok的值为true。否则为false,并且v的值为T类型的零值。 在这种情况下,不会发生运行时恐慌 。
编辑
问题 :
x.(T)当T是an
interface{}而不是具体类型时,断言返回什么?答 :
它断言x不是nil,并且x中存储的值是T类型。
例如,此恐慌(编译:成功,运行:)
panic: interface conversion: interface is nil, not interface{}:package mainfunc main() { var i interface{} // nil var _ = i.(interface{})}这可行(运行:确定):
package mainimport "fmt"func main() { var i interface{} // nil b, ok := i.(interface{}) fmt.Println(b, ok) // <nil> false i = 2 c, ok := i.(interface{}) fmt.Println(c, ok) // 2 true //var j int = c // cannot use c (type interface {}) as type int in assignment: need type assertion //fmt.Println(j)}输出:
<nil> false2 true
注意: 这里
c是类型
interface {}而不是int。
请参阅以下带有注释输出的工作示例代码:
package mainimport "fmt"func main() { const fm = "'%T't'%#[1]v't'%[1]v't%vn" var i interface{} b, ok := i.(interface{}) fmt.Printf(fm, b, ok) // '<nil>' '<nil>' '<nil>' false i = 2 b, ok = i.(interface{}) fmt.Printf(fm, b, ok) // 'int' '2' '2' true i = "Hi" b, ok = i.(interface{}) fmt.Printf(fm, b, ok) // 'string' '"Hi"' 'Hi' true i = new(interface{}) b, ok = i.(interface{}) fmt.Printf(fm, b, ok) // '*interface {}' '(*interface {})(0xc042004330)' '0xc042004330' true i = struct{}{} b, ok = i.(interface{}) fmt.Printf(fm, b, ok) // 'struct {}' 'struct {}{}' '{}' true i = fmt.Println b, ok = i.(interface{}) fmt.Printf(fm, b, ok) // 'func(...interface {}) (int, error)' '(func(...interface {}) (int, error))(0x456740)' '0x456740' true i = Shape.Area b, ok = i.(interface{}) fmt.Printf(fm, b, ok) // 'func(main.Shape) float64' '(func(main.Shape) float64)(0x401910)' '0x401910' true}type Shape interface { Area() float64}欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)