I have a interface, like this:
type Collections[T any] interface {
Add(element T) bool
Get(index uint64) T
Length() uint64
}
and I have a subclass implement the interface:
type LinkedList[T any] struct {
size uint64
head *linkedListNode[T]
tail *linkedListNode[T]
}
and I define a package function:
func IsEmpty[T any](collections Collections[T]) bool {
if collections == nil {
return true
}
return collections.Length() <= 0
}
now I have a question, if I have a constuctor like this:
func NewLinkedList[T any]() Collections[T] {
linkList := &LinkedList[T]{size: 0}
headNode := &linkedListNode[T]{}
tailNode := &linkedListNode[T]{}
headNode.next = tailNode
tailNode.pre = headNode
linkList.head = headNode
linkList.tail = tailNode
return linkList
}
then I can use the package function like this:
func TestLinkedListCreate(t *testing.T) {
var obj = datastruct.NewLinkedList[string]()
empty := datastruct.IsEmpty(obj)
println(empty)
}
but if I have a constuctor like this:
func NewLinkedList[T any]() *LinkedList[T] {
linkList := &LinkedList[T]{size: 0}
headNode := &linkedListNode[T]{}
tailNode := &linkedListNode[T]{}
headNode.next = tailNode
tailNode.pre = headNode
linkList.head = headNode
linkList.tail = tailNode
return linkList
}
I have to use package function like this:
func TestLinkedListCreate(t *testing.T) {
var obj datastruct.Collections[string] = datastruct.NewLinkedList[string]()
empty := datastruct.IsEmpty(obj)
println(empty)
}
so why golang can auto cast subclass to interface in function, but can't cast subclass to interface in declare?
I use golang 1.19
Volker said in a comment:
Go has no casts, no classes, no inheritance and no subclasses. Your question makes no sense. You cannot do traditional OOP in Go. Redesign
I am asserting that the type of a pointer to a struct is implementing an interface in golang and there is something I don't understand in the code sample below:
package main
import (
"fmt"
)
type MyStruct struct {
Name string
}
func (m *MyStruct) MyFunc() {
m.Name = "bar"
}
type MyInterface interface {
MyFunc()
}
func main() {
x := &MyStruct{
Name: "foo",
}
var y interface{}
y = x
_, ok := y.(MyInterface)
if !ok {
fmt.Println("Not MyInterface")
} else {
fmt.Println("It is MyInterface")
}
}
I was expecting to do _, ok := y.(*MyInterface) since y is a pointer to MyStruct. Why can't I assert it is a pointer?
Type assertion is used to find the type of the object contained in an interface. So, y.(MyInterface) works, because the object contained in the interface y is a *MyStruct, and it implements MyInterface. However, *MyInterface is not an interface, it is a pointer to an interface, so what you are asserting is whether y is a *MyInterface, not whether or not y implements MyInterface. This will only be successful if:
var x MyInterface
var y interface{}
y=&x
_, ok := y.(*MyInterface)
I have a function which accept all type of struct as interface. If I try to print
s.Index(i)
It gives me the values. However once I append it into
allRows []interface{}
and print it out. Instead of value I am getting the type of struct that I passed the function.
As an exapmle.
fmt.Println("AllRows",allRows)
[<adminPanel.allBeaconInfo Value> <adminPanel.allBeaconInfo Value>
<adminPanel.allBeaconInfo Value> <adminPanel.allBeaconInfo Value>
<adminPanel.allBeaconInfo Value>]
func pagination(c *gin.Context, st interface{}) {
var allRows []interface{}
switch reflect.TypeOf(st).Kind() {
case reflect.Slice:
s := reflect.ValueOf(st)
for i := 0; i < s.Len(); i++ {
allRows=append(allRows,s.Index(i))
fmt.Println(allRows)
}
}
fmt.Println("AllRows",allRows)
The expression s.Index(i) evaluates to a reflect.Value containing the actual slice element. Call Value.Interface() to get the actual slice element.
var allRows []interface{}
switch reflect.TypeOf(st).Kind() {
case reflect.Slice:
s := reflect.ValueOf(st)
for i := 0; i < s.Len(); i++ {
allRows=append(allRows,s.Index(i).Interface())
fmt.Println(allRows)
}
}
I'm trying to upload a JSON file to the SKIP (getskip.com) web server and I am getting socket error 10054. They are not very good at giving samples of how, since they think everyone is using cUrl, but we are still using Delphi XE6 with Indy.
Here is what they provided.
For Java using OK HTTP:
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
RequestBody body = RequestBody.create(mediaType, "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"path\"; filename=\"<<file_name>>\"\r\nContent-Type: application/vnd.novadigm.ext\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\n[{\"file_key\": \"path\", \"store_id\"::<<store_id>>}]\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");
Request request = new Request.Builder()
.url("https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json")
.post(body)
.addHeader("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW")
.addHeader("Authorization", "Bearer <<api_user_token>>")
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("User-Agent", "PostmanRuntime/7.13.0")
.addHeader("Accept", "*/*")
.addHeader("Cache-Control", "no-cache")
.addHeader("Postman-Token", "de9932d2-bda0-4df6-8a9a-e2d4f74c2048,d59a9861-1a65-471a-8ada-6e025e985dca")
.addHeader("Host", "upload.goskip.com:8080")
.addHeader("accept-encoding", "gzip, deflate")
.addHeader("content-length", "407")
.addHeader("Connection", "keep-alive")
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
Java using Unirest:
HttpResponse<String> response = Unirest.post("https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json")
.header("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW")
.header("Authorization", "Bearer <<api_user_token>>")
.header("Content-Type", "application/x-www-form-urlencoded")
.header("User-Agent", "PostmanRuntime/7.13.0")
.header("Accept", "*/*")
.header("Cache-Control", "no-cache")
.header("Postman-Token", "de9932d2-bda0-4df6-8a9a-e2d4f74c2048,d1ea454e-594c-4746-9de7-e813377ff095")
.header("Host", "upload.goskip.com:8080")
.header("accept-encoding", "gzip, deflate")
.header("content-length", "407")
.header("Connection", "keep-alive")
.header("cache-control", "no-cache")
.body("------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"path\"; filename=\"<<file_name>>\"\r\nContent-Type: application/vnd.novadigm.ext\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\n[{\"file_key\": \"path\", \"store_id\":<<store_id>>}]\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--")
.asString();
PHP using HttpRequest:
<?php
$request = new HttpRequest();
$request->setUrl('https://upload.goskip.com:8080/v2/backoffice/files/pricebook');
$request->setMethod(HTTP_METH_POST);
$request->setQueryData(array(
'type' => 'json'
));
$request->setHeaders(array(
'cache-control' => 'no-cache',
'Connection' => 'keep-alive',
'content-length' => '407',
'accept-encoding' => 'gzip, deflate',
'Host' => 'upload.goskip.com:8080',
'Postman-Token' => 'de9932d2-bda0-4df6-8a9a-e2d4f74c2048,c7acbc0a-6450-43d1-b4ca-bc2a56cebc4e',
'Cache-Control' => 'no-cache',
'Accept' => '*/*',
'User-Agent' => 'PostmanRuntime/7.13.0',
'Content-Type' => 'application/x-www-form-urlencoded',
'Authorization' => 'Bearer <<api_user_token>>',
'content-type' => 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
));
$request->setBody('------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="path"; filename="<<file_name>>"
Content-Type: application/vnd.novadigm.ext
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="data"
[{"file_key": "path", "store_id"::<<store_id>>}]
------WebKitFormBoundary7MA4YWxkTrZu0gW--');
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
Here is what I tried in Indy. I pasted the JSON file in to a Memo on the Form:
function TFormJsonWrite.HTTPPost: String;
var
JsonToSend : TStringStream;
Response: String;
IdHTTP1: TIdHTTP;
IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
begin
IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create;
IdHTTP1 := TIdHTTP.Create;
IdHTTP1.Request.CharSet := 'utf-8';
JsonToSend := TStringStream.Create(memolog.text, TEncoding.UTF8);
IdHTTP1.Request.ContentDisposition := 'form-data; name=[{"file_key":''' + memolog.text + ''', "store_id"::001}]------WebKitFormBoundary7MA4YWxkTrZu0gW--';
IdHTTP1.Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
IdHTTP1.Request.ContentType := 'multipart/form-data';
IdHTTP1.Request.Accept := '*/*';
IdHTTP1.Request.AcceptEncoding := 'gzip,deflate';
IdHTTP1.Request.ContentLength := -1;
IdHTTP1.Request.CacheControl := 'no-cache';
IdHTTP1.Request.Connection := 'keep-alive';
IdHTTP1.Request.BasicAuthentication := false;
IdHTTP1.Request.Host := 'upload.goskip.com:8080';
IdHTTP1.Request.CustomHeaders.Clear;
IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer eyJhbGc.......................';
IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := 'de9932d2-bda0-4df6-8a9a-e2d4f74c2048,d59a9861-1a65-471a-8ada-6e025e985dca';
IdHTTP1.ReadTimeout := 50000;
IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;
Response := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', JsonToSend);
HTTPPost := Response;
JsonToSend.Free;
IdHTTP1.Free;
end;
curl
Kim#KIMNEW MINGW64 ~
$ curl -F "file=#"C:/mydata/Items-114946.json -H "authorization:Bearer eyJ........................." https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json&store_id=001
[1] 13296
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
Kim#KIMNEW MINGW64 ~
100 951k 100 53 100 951k 53 968k 0:00:01 --:--:-- 0:00:01 967k{"message":"#/data: null value where array expected"}
They updating all their endpoints this is the latest I got.
curl -X POST 'https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json' -H 'Authorization: Bearer <api_user_token>' -F path=#<path_to_first_file> -F path1=#<path_to_second_file> -F 'data=[{"file_key":"path","store_id":<store_id_for_first_file>},{"file_key":"path1","store_id":<store_id_for_second_file>}]'
Your Delphi code is all wrong.
You are setting the wrong Content-Disposition header to the wrong value.
You are posting the JSON data as-is without wrapping it inside of MIME at all.
DO NOT set the TIdHTTP.Request.AcceptEncoding property manually. You are not setting up the TIdHTTP to enable compression support, but you are giving the server permission to send compressed responses, which TIdHTTP will not be able to decompress for you.
The correct way to send a multipart/form-data request using TIdHTTP is to use the overloaded Post() method that takes a TIdMultipartFormDataStream as input, like this:
function TFormJsonWrite.HTTPPost: String;
var
JsonToSend : String;
IdHTTP1: TIdHTTP;
IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
PostData: TIdMultipartFormDataStream;
begin
JsonToSend := '[{"file_key": "path", "store_id": <<store_id>>}]';
IdHTTP1 := TIdHTTP.Create;
try
IdHTTP1.ReadTimeout := 50000;
IdHTTP1.Request.BasicAuthentication := false;
IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ...';
IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := '...';
IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;
PostData := TIdMultipartFormDataStream.Create;
try
PostData.AddFormField('path', '', '', 'application/vnd.novadigm.ext').FileName := '<<file_name>>';
PostData.AddFormField('data', JsonToSend, 'utf-8', 'application/json').ContentTransfer := '8bit';
Result := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', PostData);
finally
PostData.Free;
end;
finally
IdHTTP1.Free;
end;
end;
If, by chance, the server has issues with how TIdMultipartFormDataStream formats the MIME data (ie, if the server rejects the MIME Content-Type and/or Content-Transfer-Encoding headers that are generated by TIdMultipartFormDataStream for each MIME field, as it does not yet conform to RFC 7578, which is used by HTML5), you can format the MIME data manually to match SKIP's examples exactly, like this:
function TFormJsonWrite.HTTPPost: String;
var
JsonToSend : String;
IdHTTP1: TIdHTTP;
IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
PostData: TStringStream;
begin
JsonToSend := '[{"file_key": "path", "store_id": <<store_id>>}]';
IdHTTP1 := TIdHTTP.Create;
try
IdHTTP1.ReadTimeout := 50000;
IdHTTP1.Request.ContentType := 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW';
IdHTTP1.Request.BasicAuthentication := false;
IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ...';
IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := '...';
IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;
PostData := TStringStream.Create(
'------WebKitFormBoundary7MA4YWxkTrZu0gW' + EOL +
'Content-Disposition: form-data; name="path"; filename="<<file_name>>"' + EOL +
'Content-Type: application/vnd.novadigm.ext' + EOL +
EOL +
EOL +
'------WebKitFormBoundary7MA4YWxkTrZu0gW' + EOL +
'Content-Disposition: form-data; name="data"' + EOL +
EOL +
JsonToSend + EOL +
'------WebKitFormBoundary7MA4YWxkTrZu0gW--',
TEncoding.UTF8
);
try
Result := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', PostData);
finally
PostData.Free;
end;
finally
IdHTTP1.Free;
end;
end;
UPDATE: based on the new curl commands you have provided, the original examples you showed do not match the commands. Try something more like this instead:
function TFormJsonWrite.HTTPPost: String;
var
JsonToSend : String;
IdHTTP1: TIdHTTP;
IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
PostData: TIdMultipartFormDataStream;
begin
JsonToSend := '[{"file_key": "path", "store_id": <<store_id>>}]';
IdHTTP1 := TIdHTTP.Create;
try
IdHTTP1.ReadTimeout := 50000;
IdHTTP1.Request.BasicAuthentication := false;
IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ...';
IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := '...';
IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;
PostData := TIdMultipartFormDataStream.Create;
try
PostData.AddFile('path', '<<path_to_file>>').ContentTransfer := 'binary';
PostData.AddFormField('data', JsonToSend, 'utf-8', 'application/json').ContentTransfer := '8bit';
Result := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', PostData);
finally
PostData.Free;
end;
finally
IdHTTP1.Free;
end;
end;
Or:
function TFormJsonWrite.HTTPPost: String;
var
JsonToSend : String;
IdHTTP1: TIdHTTP;
IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
PostData: TMemoryStream;
FS: TIdReadFileExclusiveStream;
begin
JsonToSend := '[{"file_key": "path", "store_id": <<store_id>>}]';
IdHTTP1 := TIdHTTP.Create;
try
IdHTTP1.ReadTimeout := 50000;
IdHTTP1.Request.ContentType := 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW';
IdHTTP1.Request.BasicAuthentication := false;
IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ...';
IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := '...';
IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;
PostData := TMemoryStream.Create;
try
WriteStringToStream(PostData, '------WebKitFormBoundary7MA4YWxkTrZu0gW' + EOL);
WriteStringToStream(PostData, 'Content-Disposition: form-data; name="path"; filename="<<file_name>>"' + EOL);
WriteStringToStream(PostData, 'Content-Type: ' + GetMIMETypeFromFile('<<file_name>>') + EOL);
WriteStringToStream(PostData, 'Content-Transfer-Encoding: binary' + EOL);
WriteStringToStream(PostData, EOL);
FS := TIdReadFileExclusiveStream.Create('<<path_to_file>>', fmOpenRead or fmShareDenyWrite);
try
PostData.CopyFrom(FS, 0);
finally
FS.Free;
end;
WriteStringToStream(PostData, EOL);
WriteStringToStream(PostData, '------WebKitFormBoundary7MA4YWxkTrZu0gW' + EOL);
WriteStringToStream(PostData, 'Content-Disposition: form-data; name="data"' + EOL);
WriteStringToStream(PostData, EOL);
WriteStringToStream(PostData, JsonToSend + EOL, IndyTextEncoding_UTF8);
WriteStringToStream(PostData, '------WebKitFormBoundary7MA4YWxkTrZu0gW--');
PostData.Position := 0;
Result := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', PostData);
finally
PostData.Free;
end;
finally
IdHTTP1.Free;
end;
end;
Can't get returning string value of a method called via reflection
panic: interface conversion: interface is []reflect.Value, not string
package main
import (
"reflect"
)
type API_EndPoint struct{}
func main() {
var ep API_EndPoint
s := reflect.ValueOf(&ep).MethodByName("EndPoint_X").Call([]reflect.Value{reflect.ValueOf(`foo bar`)})
v := reflect.ValueOf(s)
i := v.Interface()
a := i.(string)
println(a)
}
func (ep *API_EndPoint) EndPoint_X(params string) string {
return "this_is_a_string" + params
}
see this code in play.golang.org
.Call returns a slice of reflect.Value so to do what you're trying to do you need to do something like:
package main
import ("reflect")
type API_EndPoint struct {}
func main() {
var ep API_EndPoint
s := reflect.ValueOf(&ep).MethodByName("EndPoint_X").Call([]reflect.Value{reflect.ValueOf(`foo bar`)})
v := reflect.ValueOf(s)
i := v.Interface()
a := i.([]reflect.Value)[0].String() // Get the first index of the slice and call the .String() method on it
println(a)
}
func (ep *API_EndPoint) EndPoint_X( params string) string{
return "this_is_a_string " + params
}
https://play.golang.org/p/MtqCrshTcH
this_is_a_string foo bar
Not sure what you're trying to accomplish but that should work.